xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 4dfa11a44d5adf2389f1d3acbc8f3c1116dc6c3a)
10a96aa3bSJed Brown #include <petscds.h>
20a96aa3bSJed Brown #include <petsc/private/dmimpl.h>
30a96aa3bSJed Brown #include <petsc/private/dmforestimpl.h>
40a96aa3bSJed Brown #include <petsc/private/dmpleximpl.h>
50a96aa3bSJed Brown #include <petsc/private/dmlabelimpl.h>
60a96aa3bSJed Brown #include <petsc/private/viewerimpl.h>
70a96aa3bSJed Brown #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h>
80a96aa3bSJed Brown #include "petsc_p4est_package.h"
90a96aa3bSJed Brown 
100a96aa3bSJed Brown #if defined(PETSC_HAVE_P4EST)
110a96aa3bSJed Brown 
120a96aa3bSJed Brown #if !defined(P4_TO_P8)
130a96aa3bSJed Brown #include <p4est.h>
140a96aa3bSJed Brown #include <p4est_extended.h>
150a96aa3bSJed Brown #include <p4est_geometry.h>
160a96aa3bSJed Brown #include <p4est_ghost.h>
170a96aa3bSJed Brown #include <p4est_lnodes.h>
180a96aa3bSJed Brown #include <p4est_vtk.h>
190a96aa3bSJed Brown #include <p4est_plex.h>
200a96aa3bSJed Brown #include <p4est_bits.h>
210a96aa3bSJed Brown #include <p4est_algorithms.h>
220a96aa3bSJed Brown #else
230a96aa3bSJed Brown #include <p8est.h>
240a96aa3bSJed Brown #include <p8est_extended.h>
250a96aa3bSJed Brown #include <p8est_geometry.h>
260a96aa3bSJed Brown #include <p8est_ghost.h>
270a96aa3bSJed Brown #include <p8est_lnodes.h>
280a96aa3bSJed Brown #include <p8est_vtk.h>
290a96aa3bSJed Brown #include <p8est_plex.h>
300a96aa3bSJed Brown #include <p8est_bits.h>
310a96aa3bSJed Brown #include <p8est_algorithms.h>
320a96aa3bSJed Brown #endif
330a96aa3bSJed Brown 
349371c9d4SSatish Balay typedef enum {
359371c9d4SSatish Balay   PATTERN_HASH,
369371c9d4SSatish Balay   PATTERN_FRACTAL,
379371c9d4SSatish Balay   PATTERN_CORNER,
389371c9d4SSatish Balay   PATTERN_CENTER,
399371c9d4SSatish Balay   PATTERN_COUNT
409371c9d4SSatish Balay } DMRefinePattern;
410a96aa3bSJed Brown static const char *DMRefinePatternName[PATTERN_COUNT] = {"hash", "fractal", "corner", "center"};
420a96aa3bSJed Brown 
439371c9d4SSatish Balay typedef struct _DMRefinePatternCtx {
440a96aa3bSJed Brown   PetscInt       corner;
450a96aa3bSJed Brown   PetscBool      fractal[P4EST_CHILDREN];
460a96aa3bSJed Brown   PetscReal      hashLikelihood;
470a96aa3bSJed Brown   PetscInt       maxLevel;
480a96aa3bSJed Brown   p4est_refine_t refine_fn;
499371c9d4SSatish Balay } DMRefinePatternCtx;
500a96aa3bSJed Brown 
519371c9d4SSatish Balay static int DMRefinePattern_Corner(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) {
520a96aa3bSJed Brown   p4est_quadrant_t    root, rootcorner;
530a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
540a96aa3bSJed Brown 
550a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
560a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
570a96aa3bSJed Brown 
580a96aa3bSJed Brown   root.x = root.y = 0;
590a96aa3bSJed Brown #if defined(P4_TO_P8)
600a96aa3bSJed Brown   root.z = 0;
610a96aa3bSJed Brown #endif
620a96aa3bSJed Brown   root.level = 0;
630a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&root, &rootcorner, ctx->corner, quadrant->level);
640a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant, &rootcorner)) return 1;
650a96aa3bSJed Brown   return 0;
660a96aa3bSJed Brown }
670a96aa3bSJed Brown 
689371c9d4SSatish Balay static int DMRefinePattern_Center(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) {
690a96aa3bSJed Brown   int                 cid;
700a96aa3bSJed Brown   p4est_quadrant_t    ancestor, ancestorcorner;
710a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
720a96aa3bSJed Brown 
730a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
740a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
750a96aa3bSJed Brown   if (quadrant->level <= 1) return 1;
760a96aa3bSJed Brown 
770a96aa3bSJed Brown   p4est_quadrant_ancestor(quadrant, 1, &ancestor);
780a96aa3bSJed Brown   cid = p4est_quadrant_child_id(&ancestor);
790a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&ancestor, &ancestorcorner, P4EST_CHILDREN - 1 - cid, quadrant->level);
800a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant, &ancestorcorner)) return 1;
810a96aa3bSJed Brown   return 0;
820a96aa3bSJed Brown }
830a96aa3bSJed Brown 
849371c9d4SSatish Balay static int DMRefinePattern_Fractal(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) {
850a96aa3bSJed Brown   int                 cid;
860a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
870a96aa3bSJed Brown 
880a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
890a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
900a96aa3bSJed Brown   if (!quadrant->level) return 1;
910a96aa3bSJed Brown   cid = p4est_quadrant_child_id(quadrant);
920a96aa3bSJed Brown   if (ctx->fractal[cid ^ ((int)(quadrant->level % P4EST_CHILDREN))]) return 1;
930a96aa3bSJed Brown   return 0;
940a96aa3bSJed Brown }
950a96aa3bSJed Brown 
960a96aa3bSJed Brown /* simplified from MurmurHash3 by Austin Appleby */
970a96aa3bSJed Brown #define DMPROT32(x, y) ((x << y) | (x >> (32 - y)))
989371c9d4SSatish Balay static uint32_t DMPforestHash(const uint32_t *blocks, uint32_t nblocks) {
990a96aa3bSJed Brown   uint32_t c1   = 0xcc9e2d51;
1000a96aa3bSJed Brown   uint32_t c2   = 0x1b873593;
1010a96aa3bSJed Brown   uint32_t r1   = 15;
1020a96aa3bSJed Brown   uint32_t r2   = 13;
1030a96aa3bSJed Brown   uint32_t m    = 5;
1040a96aa3bSJed Brown   uint32_t n    = 0xe6546b64;
1050a96aa3bSJed Brown   uint32_t hash = 0;
1060a96aa3bSJed Brown   int      len  = nblocks * 4;
1070a96aa3bSJed Brown   uint32_t i;
1080a96aa3bSJed Brown 
1090a96aa3bSJed Brown   for (i = 0; i < nblocks; i++) {
1100a96aa3bSJed Brown     uint32_t k;
1110a96aa3bSJed Brown 
1120a96aa3bSJed Brown     k = blocks[i];
1130a96aa3bSJed Brown     k *= c1;
1140a96aa3bSJed Brown     k = DMPROT32(k, r1);
1150a96aa3bSJed Brown     k *= c2;
1160a96aa3bSJed Brown 
1170a96aa3bSJed Brown     hash ^= k;
1180a96aa3bSJed Brown     hash = DMPROT32(hash, r2) * m + n;
1190a96aa3bSJed Brown   }
1200a96aa3bSJed Brown 
1210a96aa3bSJed Brown   hash ^= len;
1220a96aa3bSJed Brown   hash ^= (hash >> 16);
1230a96aa3bSJed Brown   hash *= 0x85ebca6b;
1240a96aa3bSJed Brown   hash ^= (hash >> 13);
1250a96aa3bSJed Brown   hash *= 0xc2b2ae35;
1260a96aa3bSJed Brown   hash ^= (hash >> 16);
1270a96aa3bSJed Brown 
1280a96aa3bSJed Brown   return hash;
1290a96aa3bSJed Brown }
1300a96aa3bSJed Brown 
1310a96aa3bSJed Brown #if defined(UINT32_MAX)
1320a96aa3bSJed Brown #define DMP4EST_HASH_MAX UINT32_MAX
1330a96aa3bSJed Brown #else
1340a96aa3bSJed Brown #define DMP4EST_HASH_MAX ((uint32_t)0xffffffff)
1350a96aa3bSJed Brown #endif
1360a96aa3bSJed Brown 
1379371c9d4SSatish Balay static int DMRefinePattern_Hash(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) {
1380a96aa3bSJed Brown   uint32_t            data[5];
1390a96aa3bSJed Brown   uint32_t            result;
1400a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
1410a96aa3bSJed Brown 
1420a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
1430a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
1440a96aa3bSJed Brown   data[0] = ((uint32_t)quadrant->level) << 24;
1450a96aa3bSJed Brown   data[1] = (uint32_t)which_tree;
1460a96aa3bSJed Brown   data[2] = (uint32_t)quadrant->x;
1470a96aa3bSJed Brown   data[3] = (uint32_t)quadrant->y;
1480a96aa3bSJed Brown #if defined(P4_TO_P8)
1490a96aa3bSJed Brown   data[4] = (uint32_t)quadrant->z;
1500a96aa3bSJed Brown #endif
1510a96aa3bSJed Brown 
1520a96aa3bSJed Brown   result = DMPforestHash(data, 2 + P4EST_DIM);
1530a96aa3bSJed Brown   if (((double)result / (double)DMP4EST_HASH_MAX) < ctx->hashLikelihood) return 1;
1540a96aa3bSJed Brown   return 0;
1550a96aa3bSJed Brown }
1560a96aa3bSJed Brown 
1570a96aa3bSJed Brown #define DMConvert_pforest_plex _infix_pforest(DMConvert, _plex)
1580a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM, DMType, DM *);
1590a96aa3bSJed Brown 
1600a96aa3bSJed Brown #define DMFTopology_pforest _append_pforest(DMFTopology)
1610a96aa3bSJed Brown typedef struct {
1620a96aa3bSJed Brown   PetscInt              refct;
1630a96aa3bSJed Brown   p4est_connectivity_t *conn;
1640a96aa3bSJed Brown   p4est_geometry_t     *geom;
1650a96aa3bSJed Brown   PetscInt             *tree_face_to_uniq; /* p4est does not explicitly enumerate facets, but we must to keep track of labels */
1660a96aa3bSJed Brown } DMFTopology_pforest;
1670a96aa3bSJed Brown 
1680a96aa3bSJed Brown #define DM_Forest_pforest _append_pforest(DM_Forest)
1690a96aa3bSJed Brown typedef struct {
1700a96aa3bSJed Brown   DMFTopology_pforest *topo;
1710a96aa3bSJed Brown   p4est_t             *forest;
1720a96aa3bSJed Brown   p4est_ghost_t       *ghost;
1730a96aa3bSJed Brown   p4est_lnodes_t      *lnodes;
1740a96aa3bSJed Brown   PetscBool            partition_for_coarsening;
1750a96aa3bSJed Brown   PetscBool            coarsen_hierarchy;
1760a96aa3bSJed Brown   PetscBool            labelsFinalized;
1770a96aa3bSJed Brown   PetscBool            adaptivitySuccess;
1780a96aa3bSJed Brown   PetscInt             cLocalStart;
1790a96aa3bSJed Brown   PetscInt             cLocalEnd;
1800a96aa3bSJed Brown   DM                   plex;
1810a96aa3bSJed Brown   char                *ghostName;
1820a96aa3bSJed Brown   PetscSF              pointAdaptToSelfSF;
1830a96aa3bSJed Brown   PetscSF              pointSelfToAdaptSF;
1840a96aa3bSJed Brown   PetscInt            *pointAdaptToSelfCids;
1850a96aa3bSJed Brown   PetscInt            *pointSelfToAdaptCids;
1860a96aa3bSJed Brown } DM_Forest_pforest;
1870a96aa3bSJed Brown 
1880a96aa3bSJed Brown #define DM_Forest_geometry_pforest _append_pforest(DM_Forest_geometry)
1890a96aa3bSJed Brown typedef struct {
1900a96aa3bSJed Brown   DM base;
1910a96aa3bSJed Brown   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
1920a96aa3bSJed Brown   void             *mapCtx;
1930a96aa3bSJed Brown   PetscInt          coordDim;
1940a96aa3bSJed Brown   p4est_geometry_t *inner;
1959371c9d4SSatish Balay } DM_Forest_geometry_pforest;
1960a96aa3bSJed Brown 
1970a96aa3bSJed Brown #define GeometryMapping_pforest _append_pforest(GeometryMapping)
1989371c9d4SSatish Balay static void GeometryMapping_pforest(p4est_geometry_t *geom, p4est_topidx_t which_tree, const double abc[3], double xyz[3]) {
1990a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest *)geom->user;
2000a96aa3bSJed Brown   PetscReal                   PetscABC[3]  = {0.};
2010a96aa3bSJed Brown   PetscReal                   PetscXYZ[3]  = {0.};
2020a96aa3bSJed Brown   PetscInt                    i, d = PetscMin(3, geom_pforest->coordDim);
2030a96aa3bSJed Brown   double                      ABC[3];
2040a96aa3bSJed Brown   PetscErrorCode              ierr;
2050a96aa3bSJed Brown 
2060a96aa3bSJed Brown   (geom_pforest->inner->X)(geom_pforest->inner, which_tree, abc, ABC);
2070a96aa3bSJed Brown 
2080a96aa3bSJed Brown   for (i = 0; i < d; i++) PetscABC[i] = ABC[i];
2099371c9d4SSatish Balay   ierr = (geom_pforest->map)(geom_pforest->base, (PetscInt)which_tree, geom_pforest->coordDim, PetscABC, PetscXYZ, geom_pforest->mapCtx);
2109371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2110a96aa3bSJed Brown   for (i = 0; i < d; i++) xyz[i] = PetscXYZ[i];
2120a96aa3bSJed Brown }
2130a96aa3bSJed Brown 
2140a96aa3bSJed Brown #define GeometryDestroy_pforest _append_pforest(GeometryDestroy)
2159371c9d4SSatish Balay static void GeometryDestroy_pforest(p4est_geometry_t *geom) {
2160a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest *)geom->user;
2170a96aa3bSJed Brown   PetscErrorCode              ierr;
2180a96aa3bSJed Brown 
2190a96aa3bSJed Brown   p4est_geometry_destroy(geom_pforest->inner);
2209371c9d4SSatish Balay   ierr = PetscFree(geom->user);
2219371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2229371c9d4SSatish Balay   ierr = PetscFree(geom);
2239371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2240a96aa3bSJed Brown }
2250a96aa3bSJed Brown 
2260a96aa3bSJed Brown #define DMFTopologyDestroy_pforest _append_pforest(DMFTopologyDestroy)
2279371c9d4SSatish Balay static PetscErrorCode DMFTopologyDestroy_pforest(DMFTopology_pforest **topo) {
2280a96aa3bSJed Brown   PetscFunctionBegin;
2290a96aa3bSJed Brown   if (!(*topo)) PetscFunctionReturn(0);
2300a96aa3bSJed Brown   if (--((*topo)->refct) > 0) {
2310a96aa3bSJed Brown     *topo = NULL;
2320a96aa3bSJed Brown     PetscFunctionReturn(0);
2330a96aa3bSJed Brown   }
234792fecdfSBarry Smith   if ((*topo)->geom) PetscCallP4est(p4est_geometry_destroy, ((*topo)->geom));
235792fecdfSBarry Smith   PetscCallP4est(p4est_connectivity_destroy, ((*topo)->conn));
2369566063dSJacob Faibussowitsch   PetscCall(PetscFree((*topo)->tree_face_to_uniq));
2379566063dSJacob Faibussowitsch   PetscCall(PetscFree(*topo));
2380a96aa3bSJed Brown   *topo = NULL;
2390a96aa3bSJed Brown   PetscFunctionReturn(0);
2400a96aa3bSJed Brown }
2410a96aa3bSJed Brown 
2420a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *, PetscInt **);
2430a96aa3bSJed Brown 
2440a96aa3bSJed Brown #define DMFTopologyCreateBrick_pforest _append_pforest(DMFTopologyCreateBrick)
2459371c9d4SSatish Balay static PetscErrorCode DMFTopologyCreateBrick_pforest(DM dm, PetscInt N[], PetscInt P[], PetscReal B[], DMFTopology_pforest **topo, PetscBool useMorton) {
2460a96aa3bSJed Brown   double  *vertices;
2470a96aa3bSJed Brown   PetscInt i, numVerts;
2480a96aa3bSJed Brown 
2490a96aa3bSJed Brown   PetscFunctionBegin;
25028b400f6SJacob Faibussowitsch   PetscCheck(useMorton, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Lexicographic ordering not implemented yet");
251*4dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(topo));
2520a96aa3bSJed Brown 
2530a96aa3bSJed Brown   (*topo)->refct = 1;
2540a96aa3bSJed Brown #if !defined(P4_TO_P8)
255792fecdfSBarry Smith   PetscCallP4estReturn((*topo)->conn, p4est_connectivity_new_brick, ((int)N[0], (int)N[1], (P[0] == DM_BOUNDARY_NONE) ? 0 : 1, (P[1] == DM_BOUNDARY_NONE) ? 0 : 1));
2560a96aa3bSJed Brown #else
257792fecdfSBarry Smith   PetscCallP4estReturn((*topo)->conn, p8est_connectivity_new_brick, ((int)N[0], (int)N[1], (int)N[2], (P[0] == DM_BOUNDARY_NONE) ? 0 : 1, (P[1] == DM_BOUNDARY_NONE) ? 0 : 1, (P[2] == DM_BOUNDARY_NONE) ? 0 : 1));
2580a96aa3bSJed Brown #endif
2590a96aa3bSJed Brown   numVerts = (*topo)->conn->num_vertices;
2600a96aa3bSJed Brown   vertices = (*topo)->conn->vertices;
2610a96aa3bSJed Brown   for (i = 0; i < 3 * numVerts; i++) {
2620a96aa3bSJed Brown     PetscInt j = i % 3;
2630a96aa3bSJed Brown 
2640a96aa3bSJed Brown     vertices[i] = B[2 * j] + (vertices[i] / N[j]) * (B[2 * j + 1] - B[2 * j]);
2650a96aa3bSJed Brown   }
2660a96aa3bSJed Brown   (*topo)->geom = NULL;
2679566063dSJacob Faibussowitsch   PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn, &(*topo)->tree_face_to_uniq));
2680a96aa3bSJed Brown   PetscFunctionReturn(0);
2690a96aa3bSJed Brown }
2700a96aa3bSJed Brown 
2710a96aa3bSJed Brown #define DMFTopologyCreate_pforest _append_pforest(DMFTopologyCreate)
2729371c9d4SSatish Balay static PetscErrorCode DMFTopologyCreate_pforest(DM dm, DMForestTopology topologyName, DMFTopology_pforest **topo) {
2730a96aa3bSJed Brown   const char *name = (const char *)topologyName;
2740a96aa3bSJed Brown   const char *prefix;
2750a96aa3bSJed Brown   PetscBool   isBrick, isShell, isSphere, isMoebius;
2760a96aa3bSJed Brown 
2770a96aa3bSJed Brown   PetscFunctionBegin;
2780a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2790a96aa3bSJed Brown   PetscValidCharPointer(name, 2);
2800a96aa3bSJed Brown   PetscValidPointer(topo, 3);
2819566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "brick", &isBrick));
2829566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "shell", &isShell));
2839566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "sphere", &isSphere));
2849566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "moebius", &isMoebius));
2859566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2860a96aa3bSJed Brown   if (isBrick) {
2870a96aa3bSJed Brown     PetscBool flgN, flgP, flgM, flgB, useMorton = PETSC_TRUE, periodic = PETSC_FALSE;
2880a96aa3bSJed Brown     PetscInt  N[3] = {2, 2, 2}, P[3] = {0, 0, 0}, nretN = P4EST_DIM, nretP = P4EST_DIM, nretB = 2 * P4EST_DIM, i;
2894fb89dddSMatthew G. Knepley     PetscReal B[6] = {0.0, 1.0, 0.0, 1.0, 0.0, 1.0}, Lstart[3] = {0., 0., 0.}, L[3] = {-1.0, -1.0, -1.0}, maxCell[3] = {-1.0, -1.0, -1.0};
2900a96aa3bSJed Brown 
2910a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
2929566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_size", N, &nretN, &flgN));
2939566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_periodicity", P, &nretP, &flgP));
2949566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_bounds", B, &nretB, &flgB));
2959566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_use_morton_curve", &useMorton, &flgM));
2961dca8a05SBarry Smith       PetscCheck(!flgN || nretN == P4EST_DIM, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Need to give %d sizes in -dm_p4est_brick_size, gave %" PetscInt_FMT, P4EST_DIM, nretN);
2971dca8a05SBarry Smith       PetscCheck(!flgP || nretP == P4EST_DIM, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Need to give %d periodicities in -dm_p4est_brick_periodicity, gave %" PetscInt_FMT, P4EST_DIM, nretP);
2981dca8a05SBarry Smith       PetscCheck(!flgB || nretB == 2 * P4EST_DIM, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_SIZ, "Need to give %d bounds in -dm_p4est_brick_bounds, gave %" PetscInt_FMT, P4EST_DIM, nretP);
2990a96aa3bSJed Brown     }
3000a96aa3bSJed Brown     for (i = 0; i < P4EST_DIM; i++) {
3010a96aa3bSJed Brown       P[i]     = (P[i] ? DM_BOUNDARY_PERIODIC : DM_BOUNDARY_NONE);
3020a96aa3bSJed Brown       periodic = (PetscBool)(P[i] || periodic);
3030a96aa3bSJed Brown       if (!flgB) B[2 * i + 1] = N[i];
3046858538eSMatthew G. Knepley       if (P[i]) {
3054fb89dddSMatthew G. Knepley         Lstart[i]  = B[2 * i + 0];
3064fb89dddSMatthew G. Knepley         L[i]       = B[2 * i + 1] - B[2 * i + 0];
3076858538eSMatthew G. Knepley         maxCell[i] = 1.1 * (L[i] / N[i]);
3086858538eSMatthew G. Knepley       }
3090a96aa3bSJed Brown     }
3109566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreateBrick_pforest(dm, N, P, B, topo, useMorton));
3114fb89dddSMatthew G. Knepley     if (periodic) PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
3120a96aa3bSJed Brown   } else {
313*4dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(topo));
3140a96aa3bSJed Brown 
3150a96aa3bSJed Brown     (*topo)->refct = 1;
316792fecdfSBarry Smith     PetscCallP4estReturn((*topo)->conn, p4est_connectivity_new_byname, (name));
3170a96aa3bSJed Brown     (*topo)->geom = NULL;
3181baa6e33SBarry Smith     if (isMoebius) PetscCall(DMSetCoordinateDim(dm, 3));
3190a96aa3bSJed Brown #if defined(P4_TO_P8)
3200a96aa3bSJed Brown     if (isShell) {
3210a96aa3bSJed Brown       PetscReal R2 = 1., R1 = .55;
3220a96aa3bSJed Brown 
3230a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3249566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_shell_outer_radius", &R2, NULL));
3259566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_shell_inner_radius", &R1, NULL));
3260a96aa3bSJed Brown       }
327792fecdfSBarry Smith       PetscCallP4estReturn((*topo)->geom, p8est_geometry_new_shell, ((*topo)->conn, R2, R1));
3280a96aa3bSJed Brown     } else if (isSphere) {
3290a96aa3bSJed Brown       PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856;
3300a96aa3bSJed Brown 
3310a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3329566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_outer_radius", &R2, NULL));
3339566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_inner_radius", &R1, NULL));
3349566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_core_radius", &R0, NULL));
3350a96aa3bSJed Brown       }
336792fecdfSBarry Smith       PetscCallP4estReturn((*topo)->geom, p8est_geometry_new_sphere, ((*topo)->conn, R2, R1, R0));
3370a96aa3bSJed Brown     }
3380a96aa3bSJed Brown #endif
3399566063dSJacob Faibussowitsch     PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn, &(*topo)->tree_face_to_uniq));
3400a96aa3bSJed Brown   }
3410a96aa3bSJed Brown   PetscFunctionReturn(0);
3420a96aa3bSJed Brown }
3430a96aa3bSJed Brown 
3440a96aa3bSJed Brown #define DMConvert_plex_pforest _append_pforest(DMConvert_plex)
3459371c9d4SSatish Balay static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest) {
3460a96aa3bSJed Brown   MPI_Comm  comm;
3470a96aa3bSJed Brown   PetscBool isPlex;
3480a96aa3bSJed Brown   PetscInt  dim;
3490a96aa3bSJed Brown   void     *ctx;
3500a96aa3bSJed Brown 
3510a96aa3bSJed Brown   PetscFunctionBegin;
3520a96aa3bSJed Brown 
3530a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3540a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
3559566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
35628b400f6SJacob Faibussowitsch   PetscCheck(isPlex, comm, PETSC_ERR_ARG_WRONG, "Expected DM type %s, got %s", DMPLEX, ((PetscObject)dm)->type_name);
3579566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
35863a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Expected DM dimension %d, got %" PetscInt_FMT, P4EST_DIM, dim);
3599566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, pforest));
3609566063dSJacob Faibussowitsch   PetscCall(DMSetType(*pforest, DMPFOREST));
3619566063dSJacob Faibussowitsch   PetscCall(DMForestSetBaseDM(*pforest, dm));
3629566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dm, &ctx));
3639566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(*pforest, ctx));
3649566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *pforest));
3650a96aa3bSJed Brown   PetscFunctionReturn(0);
3660a96aa3bSJed Brown }
3670a96aa3bSJed Brown 
3680a96aa3bSJed Brown #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
3699371c9d4SSatish Balay static PetscErrorCode DMForestDestroy_pforest(DM dm) {
3700a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
3710a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
3720a96aa3bSJed Brown 
3730a96aa3bSJed Brown   PetscFunctionBegin;
3740a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
375792fecdfSBarry Smith   if (pforest->lnodes) PetscCallP4est(p4est_lnodes_destroy, (pforest->lnodes));
3760a96aa3bSJed Brown   pforest->lnodes = NULL;
377792fecdfSBarry Smith   if (pforest->ghost) PetscCallP4est(p4est_ghost_destroy, (pforest->ghost));
3780a96aa3bSJed Brown   pforest->ghost = NULL;
379792fecdfSBarry Smith   if (pforest->forest) PetscCallP4est(p4est_destroy, (pforest->forest));
3800a96aa3bSJed Brown   pforest->forest = NULL;
3819566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&pforest->topo));
3829566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_plex_pforest) "_C", NULL));
3839566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_pforest_plex) "_C", NULL));
3842e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
3859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
3862e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
3872e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
3889566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->ghostName));
3899566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&pforest->plex));
3909566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
3919566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
3929566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
3939566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
3949566063dSJacob Faibussowitsch   PetscCall(PetscFree(forest->data));
3950a96aa3bSJed Brown   PetscFunctionReturn(0);
3960a96aa3bSJed Brown }
3970a96aa3bSJed Brown 
3980a96aa3bSJed Brown #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
3999371c9d4SSatish Balay static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm) {
4000a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
4010a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest *)((DM_Forest *)tdm->data)->data;
4020a96aa3bSJed Brown 
4030a96aa3bSJed Brown   PetscFunctionBegin;
4040a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
4059566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&(tpforest->topo)));
4060a96aa3bSJed Brown   tpforest->topo = pforest->topo;
4070a96aa3bSJed Brown   PetscFunctionReturn(0);
4080a96aa3bSJed Brown }
4090a96aa3bSJed Brown 
4100a96aa3bSJed Brown #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
4110a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM, p4est_connectivity_t **, PetscInt **);
4120a96aa3bSJed Brown 
4139371c9d4SSatish Balay typedef struct _PforestAdaptCtx {
4140a96aa3bSJed Brown   PetscInt  maxLevel;
4150a96aa3bSJed Brown   PetscInt  minLevel;
4160a96aa3bSJed Brown   PetscInt  currLevel;
4170a96aa3bSJed Brown   PetscBool anyChange;
4189371c9d4SSatish Balay } PforestAdaptCtx;
4190a96aa3bSJed Brown 
4209371c9d4SSatish Balay static int pforest_coarsen_currlevel(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[]) {
4210a96aa3bSJed Brown   PforestAdaptCtx *ctx       = (PforestAdaptCtx *)p4est->user_pointer;
4220a96aa3bSJed Brown   PetscInt         minLevel  = ctx->minLevel;
4230a96aa3bSJed Brown   PetscInt         currLevel = ctx->currLevel;
4240a96aa3bSJed Brown 
4250a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4260a96aa3bSJed Brown   return (int)((PetscInt)quadrants[0]->level == currLevel);
4270a96aa3bSJed Brown }
4280a96aa3bSJed Brown 
4299371c9d4SSatish Balay static int pforest_coarsen_uniform(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[]) {
4300a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4310a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4320a96aa3bSJed Brown 
4330a96aa3bSJed Brown   return (int)((PetscInt)quadrants[0]->level > minLevel);
4340a96aa3bSJed Brown }
4350a96aa3bSJed Brown 
4369371c9d4SSatish Balay static int pforest_coarsen_flag_any(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[]) {
4370a96aa3bSJed Brown   PetscInt         i;
4380a96aa3bSJed Brown   PetscBool        any      = PETSC_FALSE;
4390a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4400a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4410a96aa3bSJed Brown 
4420a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4430a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4440a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
4450a96aa3bSJed Brown       any = PETSC_FALSE;
4460a96aa3bSJed Brown       break;
4470a96aa3bSJed Brown     }
4480a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
4490a96aa3bSJed Brown       any = PETSC_TRUE;
4500a96aa3bSJed Brown       break;
4510a96aa3bSJed Brown     }
4520a96aa3bSJed Brown   }
4530a96aa3bSJed Brown   return any ? 1 : 0;
4540a96aa3bSJed Brown }
4550a96aa3bSJed Brown 
4569371c9d4SSatish Balay static int pforest_coarsen_flag_all(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[]) {
4570a96aa3bSJed Brown   PetscInt         i;
4580a96aa3bSJed Brown   PetscBool        all      = PETSC_TRUE;
4590a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4600a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4610a96aa3bSJed Brown 
4620a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4630a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4640a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
4650a96aa3bSJed Brown       all = PETSC_FALSE;
4660a96aa3bSJed Brown       break;
4670a96aa3bSJed Brown     }
4680a96aa3bSJed Brown   }
4690a96aa3bSJed Brown   return all ? 1 : 0;
4700a96aa3bSJed Brown }
4710a96aa3bSJed Brown 
4729371c9d4SSatish Balay static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) {
4730a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
4740a96aa3bSJed Brown }
4750a96aa3bSJed Brown 
4769371c9d4SSatish Balay static int pforest_refine_uniform(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) {
4770a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4780a96aa3bSJed Brown   PetscInt         maxLevel = ctx->maxLevel;
4790a96aa3bSJed Brown 
4800a96aa3bSJed Brown   return ((PetscInt)quadrant->level < maxLevel);
4810a96aa3bSJed Brown }
4820a96aa3bSJed Brown 
4839371c9d4SSatish Balay static int pforest_refine_flag(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) {
4840a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4850a96aa3bSJed Brown   PetscInt         maxLevel = ctx->maxLevel;
4860a96aa3bSJed Brown 
4870a96aa3bSJed Brown   if ((PetscInt)quadrant->level >= maxLevel) return 0;
4880a96aa3bSJed Brown 
4890a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
4900a96aa3bSJed Brown }
4910a96aa3bSJed Brown 
4929371c9d4SSatish Balay static PetscErrorCode DMPforestComputeLocalCellTransferSF_loop(p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, p4est_topidx_t flt, p4est_topidx_t llt, PetscInt *toFineLeavesCount, PetscInt *toLeaves, PetscSFNode *fromRoots, PetscInt *fromFineLeavesCount, PetscInt *fromLeaves, PetscSFNode *toRoots) {
4930a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
4940a96aa3bSJed Brown   p4est_topidx_t t;
4950a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
4960a96aa3bSJed Brown 
4970a96aa3bSJed Brown   PetscFunctionBegin;
4980a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
4990a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t *)p4estFrom->trees->array)[t]);
5000a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t *)p4estTo->trees->array)[t]);
5010a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
5020a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
5030a96aa3bSJed Brown     PetscInt          numFrom   = (PetscInt)treeFrom->quadrants.elem_count;
5040a96aa3bSJed Brown     PetscInt          numTo     = (PetscInt)treeTo->quadrants.elem_count;
5050a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t *)treeFrom->quadrants.array;
5060a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t *)treeTo->quadrants.array;
5070a96aa3bSJed Brown     PetscInt          currentFrom, currentTo;
5080a96aa3bSJed Brown     PetscInt          treeOffsetFrom = (PetscInt)treeFrom->quadrants_offset;
5090a96aa3bSJed Brown     PetscInt          treeOffsetTo   = (PetscInt)treeTo->quadrants_offset;
5100a96aa3bSJed Brown     int               comp;
5110a96aa3bSJed Brown 
512792fecdfSBarry Smith     PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (firstFrom, firstTo));
51328b400f6SJacob Faibussowitsch     PetscCheck(comp, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "non-matching partitions");
5140a96aa3bSJed Brown 
5150a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
5160a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
5170a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
5180a96aa3bSJed Brown 
5190a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
5200a96aa3bSJed Brown         if (toLeaves) {
5210a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5220a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
5230a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5240a96aa3bSJed Brown         }
5250a96aa3bSJed Brown         toFineLeaves++;
5260a96aa3bSJed Brown         currentFrom++;
5270a96aa3bSJed Brown         currentTo++;
5280a96aa3bSJed Brown       } else {
5290a96aa3bSJed Brown         int fromIsAncestor;
5300a96aa3bSJed Brown 
531792fecdfSBarry Smith         PetscCallP4estReturn(fromIsAncestor, p4est_quadrant_is_ancestor, (quadFrom, quadTo));
5320a96aa3bSJed Brown         if (fromIsAncestor) {
5330a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5340a96aa3bSJed Brown 
5350a96aa3bSJed Brown           if (toLeaves) {
5360a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5370a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
5380a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5390a96aa3bSJed Brown           }
5400a96aa3bSJed Brown           toFineLeaves++;
5410a96aa3bSJed Brown           currentTo++;
542792fecdfSBarry Smith           PetscCallP4est(p4est_quadrant_last_descendant, (quadFrom, &lastDesc, quadTo->level));
543792fecdfSBarry Smith           PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (quadTo, &lastDesc));
5440a96aa3bSJed Brown           if (comp) currentFrom++;
5450a96aa3bSJed Brown         } else {
5460a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5470a96aa3bSJed Brown 
5480a96aa3bSJed Brown           if (fromLeaves) {
5490a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
5500a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
5510a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
5520a96aa3bSJed Brown           }
5530a96aa3bSJed Brown           fromFineLeaves++;
5540a96aa3bSJed Brown           currentFrom++;
555792fecdfSBarry Smith           PetscCallP4est(p4est_quadrant_last_descendant, (quadTo, &lastDesc, quadFrom->level));
556792fecdfSBarry Smith           PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (quadFrom, &lastDesc));
5570a96aa3bSJed Brown           if (comp) currentTo++;
5580a96aa3bSJed Brown         }
5590a96aa3bSJed Brown       }
5600a96aa3bSJed Brown     }
5610a96aa3bSJed Brown   }
5620a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
5630a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
5640a96aa3bSJed Brown   PetscFunctionReturn(0);
5650a96aa3bSJed Brown }
5660a96aa3bSJed Brown 
5670a96aa3bSJed Brown /* Compute the maximum level across all the trees */
5689371c9d4SSatish Balay static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev) {
5690a96aa3bSJed Brown   p4est_topidx_t     t, flt, llt;
5700a96aa3bSJed Brown   DM_Forest         *forest      = (DM_Forest *)dm->data;
5710a96aa3bSJed Brown   DM_Forest_pforest *pforest     = (DM_Forest_pforest *)forest->data;
5720a96aa3bSJed Brown   PetscInt           maxlevelloc = 0;
5730a96aa3bSJed Brown   p4est_t           *p4est;
5740a96aa3bSJed Brown 
5750a96aa3bSJed Brown   PetscFunctionBegin;
57628b400f6SJacob Faibussowitsch   PetscCheck(pforest, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing DM_Forest_pforest");
57728b400f6SJacob Faibussowitsch   PetscCheck(pforest->forest, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing p4est_t");
5780a96aa3bSJed Brown   p4est = pforest->forest;
5790a96aa3bSJed Brown   flt   = p4est->first_local_tree;
5800a96aa3bSJed Brown   llt   = p4est->last_local_tree;
5810a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
5820a96aa3bSJed Brown     p4est_tree_t *tree = &(((p4est_tree_t *)p4est->trees->array)[t]);
5830a96aa3bSJed Brown     maxlevelloc        = PetscMax((PetscInt)tree->maxlevel, maxlevelloc);
5840a96aa3bSJed Brown   }
5851c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&maxlevelloc, lev, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
5860a96aa3bSJed Brown   PetscFunctionReturn(0);
5870a96aa3bSJed Brown }
5880a96aa3bSJed Brown 
5890a96aa3bSJed Brown /* Puts identity in coarseToFine */
5900a96aa3bSJed Brown /* assumes a matching partition */
5919371c9d4SSatish Balay static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine) {
5920a96aa3bSJed Brown   p4est_topidx_t flt, llt;
5930a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
5940a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
5950a96aa3bSJed Brown   PetscInt      *fromLeaves = NULL, *toLeaves = NULL;
5960a96aa3bSJed Brown   PetscSFNode   *fromRoots = NULL, *toRoots = NULL;
5970a96aa3bSJed Brown 
5980a96aa3bSJed Brown   PetscFunctionBegin;
5990a96aa3bSJed Brown   flt = p4estFrom->first_local_tree;
6000a96aa3bSJed Brown   llt = p4estFrom->last_local_tree;
6019566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &fromCoarse));
60248a46eb9SPierre Jolivet   if (toCoarseFromFine) PetscCall(PetscSFCreate(comm, &toCoarse));
6030a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
6040a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
6059566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom, FromOffset, p4estTo, ToOffset, flt, llt, &numLeavesTo, NULL, NULL, &numLeavesFrom, NULL, NULL));
6069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo, &toLeaves));
6079566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo, &fromRoots));
6080a96aa3bSJed Brown   if (toCoarseFromFine) {
6099566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom, &fromLeaves));
6109566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom, &fromRoots));
6110a96aa3bSJed Brown   }
6129566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom, FromOffset, p4estTo, ToOffset, flt, llt, &numLeavesTo, toLeaves, fromRoots, &numLeavesFrom, fromLeaves, toRoots));
6130a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
6149566063dSJacob Faibussowitsch     PetscCall(PetscFree(toLeaves));
6159566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(fromCoarse, numRootsFrom, numLeavesTo, NULL, PETSC_OWN_POINTER, fromRoots, PETSC_OWN_POINTER));
6161baa6e33SBarry Smith   } else PetscCall(PetscSFSetGraph(fromCoarse, numRootsFrom, numLeavesTo, toLeaves, PETSC_OWN_POINTER, fromRoots, PETSC_OWN_POINTER));
6170a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
6180a96aa3bSJed Brown   if (toCoarseFromFine) {
6199566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(toCoarse, numRootsTo, numLeavesFrom, fromLeaves, PETSC_OWN_POINTER, toRoots, PETSC_OWN_POINTER));
6200a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
6210a96aa3bSJed Brown   }
6220a96aa3bSJed Brown   PetscFunctionReturn(0);
6230a96aa3bSJed Brown }
6240a96aa3bSJed Brown 
6250a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
6269371c9d4SSatish Balay static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB) {
6270a96aa3bSJed Brown   p4est_quadrant_t *myCoarseStart = &(p4estA->global_first_position[rank]);
6280a96aa3bSJed Brown   p4est_quadrant_t *myCoarseEnd   = &(p4estA->global_first_position[rank + 1]);
6290a96aa3bSJed Brown   p4est_quadrant_t *globalFirstB  = p4estB->global_first_position;
6300a96aa3bSJed Brown 
6310a96aa3bSJed Brown   PetscFunctionBegin;
6320a96aa3bSJed Brown   *startB = -1;
6330a96aa3bSJed Brown   *endB   = -1;
6340a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
6350a96aa3bSJed Brown     PetscInt lo, hi, guess;
6360a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
6370a96aa3bSJed Brown     lo    = 0;
6380a96aa3bSJed Brown     hi    = size;
6390a96aa3bSJed Brown     guess = rank;
6400a96aa3bSJed Brown     while (1) {
6410a96aa3bSJed Brown       int startCompMy, myCompEnd;
6420a96aa3bSJed Brown 
643792fecdfSBarry Smith       PetscCallP4estReturn(startCompMy, p4est_quadrant_compare_piggy, (&globalFirstB[guess], myCoarseStart));
644792fecdfSBarry Smith       PetscCallP4estReturn(myCompEnd, p4est_quadrant_compare_piggy, (myCoarseStart, &globalFirstB[guess + 1]));
6450a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
6460a96aa3bSJed Brown         *startB = guess;
6470a96aa3bSJed Brown         break;
6480a96aa3bSJed Brown       } else if (startCompMy > 0) { /* guess is to high */
6490a96aa3bSJed Brown         hi = guess;
6500a96aa3bSJed Brown       } else { /* guess is to low */
6510a96aa3bSJed Brown         lo = guess + 1;
6520a96aa3bSJed Brown       }
6530a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6540a96aa3bSJed Brown     }
6550a96aa3bSJed Brown     /* reset bounds, but not guess */
6560a96aa3bSJed Brown     lo = 0;
6570a96aa3bSJed Brown     hi = size;
6580a96aa3bSJed Brown     while (1) {
6590a96aa3bSJed Brown       int startCompMy, myCompEnd;
6600a96aa3bSJed Brown 
661792fecdfSBarry Smith       PetscCallP4estReturn(startCompMy, p4est_quadrant_compare_piggy, (&globalFirstB[guess], myCoarseEnd));
662792fecdfSBarry Smith       PetscCallP4estReturn(myCompEnd, p4est_quadrant_compare_piggy, (myCoarseEnd, &globalFirstB[guess + 1]));
6630a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
6640a96aa3bSJed Brown         *endB = guess + 1;
6650a96aa3bSJed Brown         break;
6660a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
6670a96aa3bSJed Brown         hi = guess;
6680a96aa3bSJed Brown       } else { /* guess is to low */
6690a96aa3bSJed Brown         lo = guess + 1;
6700a96aa3bSJed Brown       }
6710a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6720a96aa3bSJed Brown     }
6730a96aa3bSJed Brown   }
6740a96aa3bSJed Brown   PetscFunctionReturn(0);
6750a96aa3bSJed Brown }
6760a96aa3bSJed Brown 
6770a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM, DM *);
6780a96aa3bSJed Brown 
6790a96aa3bSJed Brown #define DMSetUp_pforest _append_pforest(DMSetUp)
6809371c9d4SSatish Balay static PetscErrorCode DMSetUp_pforest(DM dm) {
6810a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
6820a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
6830a96aa3bSJed Brown   DM                 base, adaptFrom;
6840a96aa3bSJed Brown   DMForestTopology   topoName;
6850a96aa3bSJed Brown   PetscSF            preCoarseToFine = NULL, coarseToPreFine = NULL;
6860a96aa3bSJed Brown   PforestAdaptCtx    ctx;
6870a96aa3bSJed Brown 
6880a96aa3bSJed Brown   PetscFunctionBegin;
6890a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
6900a96aa3bSJed Brown   ctx.maxLevel  = 0;
6910a96aa3bSJed Brown   ctx.currLevel = 0;
6920a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
6930a96aa3bSJed Brown   /* sanity check */
6949566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm, &adaptFrom));
6959566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
6969566063dSJacob Faibussowitsch   PetscCall(DMForestGetTopology(dm, &topoName));
6971dca8a05SBarry Smith   PetscCheck(adaptFrom || base || topoName, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "A forest needs a topology, a base DM, or a DM to adapt from");
6980a96aa3bSJed Brown 
6990a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
7000a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
7010a96aa3bSJed Brown     PetscBool          ispforest;
7020a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest *)adaptFrom->data;
7030a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest *)aforest->data;
7040a96aa3bSJed Brown 
7059566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)adaptFrom, DMPFOREST, &ispforest));
70628b400f6SJacob Faibussowitsch     PetscCheck(ispforest, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NOTSAMETYPE, "Trying to adapt from %s, which is not %s", ((PetscObject)adaptFrom)->type_name, DMPFOREST);
70728b400f6SJacob Faibussowitsch     PetscCheck(apforest->topo, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "The pre-adaptation forest must have a topology");
7089566063dSJacob Faibussowitsch     PetscCall(DMSetUp(adaptFrom));
7099566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm, &base));
7109566063dSJacob Faibussowitsch     PetscCall(DMForestGetTopology(dm, &topoName));
7110a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
7120a96aa3bSJed Brown     PetscBool isPlex, isDA;
7130a96aa3bSJed Brown 
7149566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)base, &topoName));
7159566063dSJacob Faibussowitsch     PetscCall(DMForestSetTopology(dm, topoName));
7169566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base, DMPLEX, &isPlex));
7179566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base, DMDA, &isDA));
7180a96aa3bSJed Brown     if (isPlex) {
7190a96aa3bSJed Brown       MPI_Comm              comm = PetscObjectComm((PetscObject)dm);
7200a96aa3bSJed Brown       PetscInt              depth;
7210a96aa3bSJed Brown       PetscMPIInt           size;
7220a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
7230a96aa3bSJed Brown       DMFTopology_pforest  *topo;
7240a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
7250a96aa3bSJed Brown 
7269566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepth(base, &depth));
7270a96aa3bSJed Brown       if (depth == 1) {
7280a96aa3bSJed Brown         DM connDM;
7290a96aa3bSJed Brown 
7309566063dSJacob Faibussowitsch         PetscCall(DMPlexInterpolate(base, &connDM));
7310a96aa3bSJed Brown         base = connDM;
7329566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm, base));
7339566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&connDM));
73463a3b9bcSJacob Faibussowitsch       } else PetscCheck(depth == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Base plex is neither interpolated nor uninterpolated? depth %" PetscInt_FMT ", expected 2 or %d", depth, P4EST_DIM + 1);
7359566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(comm, &size));
7360a96aa3bSJed Brown       if (size > 1) {
7370a96aa3bSJed Brown         DM      dmRedundant;
7380a96aa3bSJed Brown         PetscSF sf;
7390a96aa3bSJed Brown 
7409566063dSJacob Faibussowitsch         PetscCall(DMPlexGetRedundantDM(base, &sf, &dmRedundant));
74128b400f6SJacob Faibussowitsch         PetscCheck(dmRedundant, comm, PETSC_ERR_PLIB, "Could not create redundant DM");
7429566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)dmRedundant, "_base_migration_sf", (PetscObject)sf));
7439566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&sf));
7440a96aa3bSJed Brown         base = dmRedundant;
7459566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm, base));
7469566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&dmRedundant));
7470a96aa3bSJed Brown       }
7489566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(base, NULL, "-dm_p4est_base_view"));
7499566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateConnectivity_pforest(base, &conn, &tree_face_to_uniq));
750*4dfa11a4SJacob Faibussowitsch       PetscCall(PetscNew(&topo));
7510a96aa3bSJed Brown       topo->refct = 1;
7520a96aa3bSJed Brown       topo->conn  = conn;
7530a96aa3bSJed Brown       topo->geom  = NULL;
7540a96aa3bSJed Brown       {
7550a96aa3bSJed Brown         PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
7560a96aa3bSJed Brown         void *mapCtx;
7570a96aa3bSJed Brown 
7589566063dSJacob Faibussowitsch         PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
7590a96aa3bSJed Brown         if (map) {
7600a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
7610a96aa3bSJed Brown           p4est_geometry_t           *geom;
7620a96aa3bSJed Brown 
7639566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom_pforest));
7649566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinateDim(dm, &geom_pforest->coordDim));
7650a96aa3bSJed Brown           geom_pforest->map    = map;
7660a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
767792fecdfSBarry Smith           PetscCallP4estReturn(geom_pforest->inner, p4est_geometry_new_connectivity, (conn));
7689566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom));
7690a96aa3bSJed Brown           geom->name    = topoName;
7700a96aa3bSJed Brown           geom->user    = geom_pforest;
7710a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
7720a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
7730a96aa3bSJed Brown           topo->geom    = geom;
7740a96aa3bSJed Brown         }
7750a96aa3bSJed Brown       }
7760a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
7770a96aa3bSJed Brown       pforest->topo           = topo;
77828b400f6SJacob Faibussowitsch     } else PetscCheck(!isDA, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Not implemented yet");
7790a96aa3bSJed Brown #if 0
7800a96aa3bSJed Brown       PetscInt N[3], P[3];
7810a96aa3bSJed Brown 
7820a96aa3bSJed Brown       /* get the sizes, periodicities */
7830a96aa3bSJed Brown       /* ... */
7840a96aa3bSJed Brown                                                                   /* don't use Morton order */
7859566063dSJacob Faibussowitsch       PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE));
7860a96aa3bSJed Brown #endif
7870a96aa3bSJed Brown     {
7880a96aa3bSJed Brown       PetscInt numLabels, l;
7890a96aa3bSJed Brown 
7909566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(base, &numLabels));
7910a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
7920a96aa3bSJed Brown         PetscBool   isDepth, isGhost, isVTK, isDim, isCellType;
7930a96aa3bSJed Brown         DMLabel     label, labelNew;
7940a96aa3bSJed Brown         PetscInt    defVal;
7950a96aa3bSJed Brown         const char *name;
7960a96aa3bSJed Brown 
7979566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(base, l, &name));
7989566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(base, l, &label));
7999566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "depth", &isDepth));
8000a96aa3bSJed Brown         if (isDepth) continue;
8019566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "dim", &isDim));
8020a96aa3bSJed Brown         if (isDim) continue;
8039566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "celltype", &isCellType));
8040a96aa3bSJed Brown         if (isCellType) continue;
8059566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "ghost", &isGhost));
8060a96aa3bSJed Brown         if (isGhost) continue;
8079566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "vtk", &isVTK));
8080a96aa3bSJed Brown         if (isVTK) continue;
8099566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm, name));
8109566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm, name, &labelNew));
8119566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label, &defVal));
8129566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
8130a96aa3bSJed Brown       }
8140a96aa3bSJed Brown       /* map dm points (internal plex) to base
8150a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
8160a96aa3bSJed Brown          and propagating back to the coarsest
8170a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
8180a96aa3bSJed Brown          during DMForestTransferVecFromBase */
8199566063dSJacob Faibussowitsch       PetscCall(DMForestGetMinimumRefinement(dm, &l));
82048a46eb9SPierre Jolivet       if (!l) PetscCall(DMCreateLabel(dm, "_forest_base_subpoint_map"));
8210a96aa3bSJed Brown     }
8220a96aa3bSJed Brown   } else { /* construct from topology name */
8230a96aa3bSJed Brown     DMFTopology_pforest *topo;
8240a96aa3bSJed Brown 
8259566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreate_pforest(dm, topoName, &topo));
8260a96aa3bSJed Brown     pforest->topo = topo;
8270a96aa3bSJed Brown     /* TODO: construct base? */
8280a96aa3bSJed Brown   }
8290a96aa3bSJed Brown 
8300a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
8310a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
8320a96aa3bSJed Brown     DMLabel            adaptLabel;
8330a96aa3bSJed Brown     PetscInt           defaultValue;
8340a96aa3bSJed Brown     PetscInt           numValues, numValuesGlobal, cLocalStart, count;
8350a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest *)adaptFrom->data;
8360a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest *)aforest->data;
8370a96aa3bSJed Brown     PetscBool          computeAdaptSF;
8380a96aa3bSJed Brown     p4est_topidx_t     flt, llt, t;
8390a96aa3bSJed Brown 
8400a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
8410a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
8420a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
8439566063dSJacob Faibussowitsch     PetscCall(DMForestGetComputeAdaptivitySF(dm, &computeAdaptSF));
844792fecdfSBarry Smith     PetscCallP4estReturn(pforest->forest, p4est_copy, (apforest->forest, 0)); /* 0 indicates no data copying */
8459566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm, &adaptLabel));
8460a96aa3bSJed Brown     if (adaptLabel) {
8470a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
8489566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(adaptLabel, &numValues));
8499566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&numValues, &numValuesGlobal, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)adaptFrom)));
8509566063dSJacob Faibussowitsch       PetscCall(DMLabelGetDefaultValue(adaptLabel, &defaultValue));
8510a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
8529566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8539566063dSJacob Faibussowitsch         PetscCall(DMPforestGetRefinementLevel(dm, &ctx.currLevel));
8540a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
855792fecdfSBarry Smith         PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_currlevel, NULL));
8560a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
857792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8580a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
85948a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), pforest->forest, 0, apforest->forest, apforest->cLocalStart, &coarseToPreFine, NULL));
8600a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */
8619566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8620a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
863792fecdfSBarry Smith         PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_uniform, NULL));
8640a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
865792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8660a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
86748a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), pforest->forest, 0, apforest->forest, apforest->cLocalStart, &coarseToPreFine, NULL));
8680a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
8699566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &ctx.maxLevel));
8700a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
871792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 0, pforest_refine_uniform, NULL));
8720a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
873792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8740a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
87548a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), apforest->forest, apforest->cLocalStart, pforest->forest, 0, &preCoarseToFine, NULL));
8760a96aa3bSJed Brown       } else if (numValuesGlobal) {
8770a96aa3bSJed Brown         p4est_t                   *p4est = pforest->forest;
8780a96aa3bSJed Brown         PetscInt                  *cellFlags;
8790a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
8800a96aa3bSJed Brown         PetscSF                    cellSF;
8810a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
8820a96aa3bSJed Brown         PetscBool                  adaptAny;
8830a96aa3bSJed Brown 
8849566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &ctx.maxLevel));
8859566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8869566063dSJacob Faibussowitsch         PetscCall(DMForestGetAdaptivityStrategy(dm, &strategy));
8879566063dSJacob Faibussowitsch         PetscCall(PetscStrncmp(strategy, "any", 3, &adaptAny));
8889566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellChart(adaptFrom, &cStart, &cEnd));
8899566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellSF(adaptFrom, &cellSF));
8909566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cEnd - cStart, &cellFlags));
8919566063dSJacob Faibussowitsch         for (c = cStart; c < cEnd; c++) PetscCall(DMLabelGetValue(adaptLabel, c, &cellFlags[c - cStart]));
8920a96aa3bSJed Brown         if (cellSF) {
8930a96aa3bSJed Brown           if (adaptAny) {
8949566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MAX));
8959566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MAX));
8960a96aa3bSJed Brown           } else {
8979566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MIN));
8989566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MIN));
8990a96aa3bSJed Brown           }
9000a96aa3bSJed Brown         }
9010a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
9020a96aa3bSJed Brown           p4est_tree_t     *tree     = &(((p4est_tree_t *)p4est->trees->array)[t]);
9030a96aa3bSJed Brown           PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count, i;
9040a96aa3bSJed Brown           p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
9050a96aa3bSJed Brown 
9060a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9070a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
9080a96aa3bSJed Brown             q->p.user_int       = cellFlags[count++];
9090a96aa3bSJed Brown           }
9100a96aa3bSJed Brown         }
9119566063dSJacob Faibussowitsch         PetscCall(PetscFree(cellFlags));
9120a96aa3bSJed Brown 
9130a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
914792fecdfSBarry Smith         if (adaptAny) PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_flag_any, pforest_init_determine));
915792fecdfSBarry Smith         else PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_flag_all, pforest_init_determine));
916792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 0, pforest_refine_flag, NULL));
9170a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
918792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
91948a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), apforest->forest, apforest->cLocalStart, pforest->forest, 0, &preCoarseToFine, &coarseToPreFine));
9200a96aa3bSJed Brown       }
9210a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
9220a96aa3bSJed Brown         p4est_tree_t     *atree     = &(((p4est_tree_t *)apforest->forest->trees->array)[t]);
9230a96aa3bSJed Brown         p4est_tree_t     *tree      = &(((p4est_tree_t *)pforest->forest->trees->array)[t]);
9240a96aa3bSJed Brown         PetscInt          anumQuads = (PetscInt)atree->quadrants.elem_count, i;
9250a96aa3bSJed Brown         PetscInt          numQuads  = (PetscInt)tree->quadrants.elem_count;
9260a96aa3bSJed Brown         p4est_quadrant_t *aquads    = (p4est_quadrant_t *)atree->quadrants.array;
9270a96aa3bSJed Brown         p4est_quadrant_t *quads     = (p4est_quadrant_t *)tree->quadrants.array;
9280a96aa3bSJed Brown 
9290a96aa3bSJed Brown         if (anumQuads != numQuads) {
9300a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
9310a96aa3bSJed Brown         } else {
9320a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9330a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
9340a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
9350a96aa3bSJed Brown 
9360a96aa3bSJed Brown             if (aq->level != q->level) {
9370a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
9380a96aa3bSJed Brown               break;
9390a96aa3bSJed Brown             }
9400a96aa3bSJed Brown           }
9410a96aa3bSJed Brown         }
942ad540459SPierre Jolivet         if (ctx.anyChange) break;
9430a96aa3bSJed Brown       }
9440a96aa3bSJed Brown     }
9450a96aa3bSJed Brown     {
9460a96aa3bSJed Brown       PetscInt numLabels, l;
9470a96aa3bSJed Brown 
9489566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(adaptFrom, &numLabels));
9490a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
9500a96aa3bSJed Brown         PetscBool   isDepth, isCellType, isGhost, isVTK;
9510a96aa3bSJed Brown         DMLabel     label, labelNew;
9520a96aa3bSJed Brown         PetscInt    defVal;
9530a96aa3bSJed Brown         const char *name;
9540a96aa3bSJed Brown 
9559566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(adaptFrom, l, &name));
9569566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(adaptFrom, l, &label));
9579566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "depth", &isDepth));
9580a96aa3bSJed Brown         if (isDepth) continue;
9599566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "celltype", &isCellType));
9600a96aa3bSJed Brown         if (isCellType) continue;
9619566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "ghost", &isGhost));
9620a96aa3bSJed Brown         if (isGhost) continue;
9639566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "vtk", &isVTK));
9640a96aa3bSJed Brown         if (isVTK) continue;
9659566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm, name));
9669566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm, name, &labelNew));
9679566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label, &defVal));
9689566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
9690a96aa3bSJed Brown       }
9700a96aa3bSJed Brown     }
9710a96aa3bSJed Brown   } else { /* initial */
9720a96aa3bSJed Brown     PetscInt initLevel, minLevel;
97366c0a4b5SToby Isaac #if defined(PETSC_HAVE_MPIUNI)
97466c0a4b5SToby Isaac     sc_MPI_Comm comm = sc_MPI_COMM_WORLD;
97566c0a4b5SToby Isaac #else
97666c0a4b5SToby Isaac     MPI_Comm comm = PetscObjectComm((PetscObject)dm);
97766c0a4b5SToby Isaac #endif
9780a96aa3bSJed Brown 
9799566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm, &initLevel));
9809566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
9819371c9d4SSatish Balay     PetscCallP4estReturn(pforest->forest, p4est_new_ext,
9829371c9d4SSatish Balay                          (comm, pforest->topo->conn, 0, /* minimum number of quadrants per processor */
9830a96aa3bSJed Brown                           initLevel,                    /* level of refinement */
9840a96aa3bSJed Brown                           1,                            /* uniform refinement */
9850a96aa3bSJed Brown                           0,                            /* we don't allocate any per quadrant data */
9860a96aa3bSJed Brown                           NULL,                         /* there is no special quadrant initialization */
9870a96aa3bSJed Brown                           (void *)dm));                 /* this dm is the user context */
9880a96aa3bSJed Brown 
9890a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
9900a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
9910a96aa3bSJed Brown       PetscBool   flgPattern, flgFractal;
9920a96aa3bSJed Brown       PetscInt    corner = 0;
9930a96aa3bSJed Brown       PetscInt    corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
9940a96aa3bSJed Brown       PetscReal   likelihood = 1. / P4EST_DIM;
9950a96aa3bSJed Brown       PetscInt    pattern;
9960a96aa3bSJed Brown       const char *prefix;
9970a96aa3bSJed Brown 
9989566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
9999566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEList(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_pattern", DMRefinePatternName, PATTERN_COUNT, &pattern, &flgPattern));
10009566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_corner", &corner, NULL));
10019566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_fractal_corners", corners, &ncorner, &flgFractal));
10029566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_hash_likelihood", &likelihood, NULL));
10030a96aa3bSJed Brown 
10040a96aa3bSJed Brown       if (flgPattern) {
10050a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
10060a96aa3bSJed Brown         PetscInt            maxLevel;
10070a96aa3bSJed Brown 
10089566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &maxLevel));
1009*4dfa11a4SJacob Faibussowitsch         PetscCall(PetscNew(&ctx));
10100a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel, P4EST_QMAXLEVEL);
10110a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10120a96aa3bSJed Brown         switch (pattern) {
10130a96aa3bSJed Brown         case PATTERN_HASH:
10140a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
10150a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
10160a96aa3bSJed Brown           break;
10170a96aa3bSJed Brown         case PATTERN_CORNER:
10180a96aa3bSJed Brown           ctx->corner    = corner;
10190a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
10200a96aa3bSJed Brown           break;
10219371c9d4SSatish Balay         case PATTERN_CENTER: ctx->refine_fn = DMRefinePattern_Center; break;
10220a96aa3bSJed Brown         case PATTERN_FRACTAL:
10230a96aa3bSJed Brown           if (flgFractal) {
10240a96aa3bSJed Brown             PetscInt i;
10250a96aa3bSJed Brown 
10260a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
10270a96aa3bSJed Brown           } else {
10280a96aa3bSJed Brown #if !defined(P4_TO_P8)
10290a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
10300a96aa3bSJed Brown #else
10310a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
10320a96aa3bSJed Brown #endif
10330a96aa3bSJed Brown           }
10340a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
10350a96aa3bSJed Brown           break;
10369371c9d4SSatish Balay         default: SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Not a valid refinement pattern");
10370a96aa3bSJed Brown         }
10380a96aa3bSJed Brown 
10390a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)ctx;
1040792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 1, ctx->refine_fn, NULL));
1041792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
10429566063dSJacob Faibussowitsch         PetscCall(PetscFree(ctx));
10430a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
10440a96aa3bSJed Brown       }
10450a96aa3bSJed Brown     }
10460a96aa3bSJed Brown   }
10470a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
10480a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
10490a96aa3bSJed Brown 
10509566063dSJacob Faibussowitsch     PetscCall(DMPforestGetRefinementLevel(dm, &currLevel));
10519566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm, &initLevel));
10529566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
10530a96aa3bSJed Brown     if (currLevel > minLevel) {
10540a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
10550a96aa3bSJed Brown       DMLabel            coarsen;
10560a96aa3bSJed Brown       DM                 coarseDM;
10570a96aa3bSJed Brown 
10589566063dSJacob Faibussowitsch       PetscCall(DMForestTemplate(dm, MPI_COMM_NULL, &coarseDM));
10599566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityPurpose(coarseDM, DM_ADAPT_COARSEN));
10609566063dSJacob Faibussowitsch       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
10619566063dSJacob Faibussowitsch       PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
10629566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityLabel(coarseDM, coarsen));
10639566063dSJacob Faibussowitsch       PetscCall(DMLabelDestroy(&coarsen));
10649566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm, coarseDM));
10659566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)coarseDM));
10660a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
10679566063dSJacob Faibussowitsch       PetscCall(DMForestSetInitialRefinement(coarseDM, initLevel));
10689566063dSJacob Faibussowitsch       PetscCall(DMForestSetMinimumRefinement(coarseDM, minLevel));
10690a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest *)((DM_Forest *)coarseDM->data)->data;
10700a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
10710a96aa3bSJed Brown     }
10720a96aa3bSJed Brown   }
10730a96aa3bSJed Brown 
10740a96aa3bSJed Brown   { /* repartitioning and overlap */
10750a96aa3bSJed Brown     PetscMPIInt size, rank;
10760a96aa3bSJed Brown 
10779566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
10789566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
10790a96aa3bSJed Brown     if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
10800a96aa3bSJed Brown       PetscBool      copyForest  = PETSC_FALSE;
10810a96aa3bSJed Brown       p4est_t       *forest_copy = NULL;
10820a96aa3bSJed Brown       p4est_gloidx_t shipped     = 0;
10830a96aa3bSJed Brown 
10840a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
1085792fecdfSBarry Smith       if (copyForest) PetscCallP4estReturn(forest_copy, p4est_copy, (pforest->forest, 0));
10860a96aa3bSJed Brown 
10870a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
1088792fecdfSBarry Smith         PetscCallP4estReturn(shipped, p4est_partition_ext, (pforest->forest, (int)pforest->partition_for_coarsening, NULL));
10890a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Non-uniform partition cases not implemented yet");
10900a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
10910a96aa3bSJed Brown       if (forest_copy) {
10920a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
10930a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
10940a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
10950a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
10960a96aa3bSJed Brown           PetscSFNode   *repartRoots;
10970a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
10980a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank + 1];
10990a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
11000a96aa3bSJed Brown 
11010a96aa3bSJed Brown           numRoots  = (PetscInt)(forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
11020a96aa3bSJed Brown           numLeaves = (PetscInt)(postEnd - postStart);
11039566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeOverlappingRanks(size, rank, pforest->forest, forest_copy, &pStart, &pEnd));
11049566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1((PetscInt)pforest->forest->local_num_quadrants, &repartRoots));
11050a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
11060a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
11070a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p + 1];
11080a96aa3bSJed Brown             PetscInt       q;
11090a96aa3bSJed Brown 
11100a96aa3bSJed Brown             if (preEnd == preStart) continue;
111108401ef6SPierre Jolivet             PetscCheck(preStart <= postStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad partition overlap computation");
11120a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
11130a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
11140a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
11150a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
11160a96aa3bSJed Brown             }
11170a96aa3bSJed Brown             partOffset = preEnd;
11180a96aa3bSJed Brown           }
11199566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &repartSF));
11209566063dSJacob Faibussowitsch           PetscCall(PetscSFSetGraph(repartSF, numRoots, numLeaves, NULL, PETSC_OWN_POINTER, repartRoots, PETSC_OWN_POINTER));
11219566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(repartSF));
11220a96aa3bSJed Brown           if (preCoarseToFine) {
11230a96aa3bSJed Brown             PetscSF         repartSFembed, preCoarseToFineNew;
11240a96aa3bSJed Brown             PetscInt        nleaves;
11250a96aa3bSJed Brown             const PetscInt *leaves;
11260a96aa3bSJed Brown 
11279566063dSJacob Faibussowitsch             PetscCall(PetscSFSetUp(preCoarseToFine));
11289566063dSJacob Faibussowitsch             PetscCall(PetscSFGetGraph(preCoarseToFine, NULL, &nleaves, &leaves, NULL));
11290a96aa3bSJed Brown             if (leaves) {
11309566063dSJacob Faibussowitsch               PetscCall(PetscSFCreateEmbeddedRootSF(repartSF, nleaves, leaves, &repartSFembed));
11310a96aa3bSJed Brown             } else {
11320a96aa3bSJed Brown               repartSFembed = repartSF;
11339566063dSJacob Faibussowitsch               PetscCall(PetscObjectReference((PetscObject)repartSFembed));
11340a96aa3bSJed Brown             }
11359566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(preCoarseToFine, repartSFembed, &preCoarseToFineNew));
11369566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&preCoarseToFine));
11379566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFembed));
11380a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
11390a96aa3bSJed Brown           }
11400a96aa3bSJed Brown           if (coarseToPreFine) {
11410a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
11420a96aa3bSJed Brown 
11439566063dSJacob Faibussowitsch             PetscCall(PetscSFCreateInverseSF(repartSF, &repartSFinv));
11449566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(repartSFinv, coarseToPreFine, &coarseToPreFineNew));
11459566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&coarseToPreFine));
11469566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFinv));
11470a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
11480a96aa3bSJed Brown           }
11499566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&repartSF));
11500a96aa3bSJed Brown         }
1151792fecdfSBarry Smith         PetscCallP4est(p4est_destroy, (forest_copy));
11520a96aa3bSJed Brown       }
11530a96aa3bSJed Brown     }
11540a96aa3bSJed Brown     if (size > 1) {
11550a96aa3bSJed Brown       PetscInt overlap;
11560a96aa3bSJed Brown 
11579566063dSJacob Faibussowitsch       PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
11580a96aa3bSJed Brown 
11590a96aa3bSJed Brown       if (adaptFrom) {
11600a96aa3bSJed Brown         PetscInt aoverlap;
11610a96aa3bSJed Brown 
11629566063dSJacob Faibussowitsch         PetscCall(DMForestGetPartitionOverlap(adaptFrom, &aoverlap));
1163ad540459SPierre Jolivet         if (aoverlap != overlap) ctx.anyChange = PETSC_TRUE;
11640a96aa3bSJed Brown       }
11650a96aa3bSJed Brown 
11660a96aa3bSJed Brown       if (overlap > 0) {
11670a96aa3bSJed Brown         PetscInt i, cLocalStart;
11680a96aa3bSJed Brown         PetscInt cEnd;
11690a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
11700a96aa3bSJed Brown 
1171792fecdfSBarry Smith         PetscCallP4estReturn(pforest->ghost, p4est_ghost_new, (pforest->forest, P4EST_CONNECT_FULL));
1172792fecdfSBarry Smith         PetscCallP4estReturn(pforest->lnodes, p4est_lnodes_new, (pforest->forest, pforest->ghost, -P4EST_DIM));
1173792fecdfSBarry Smith         PetscCallP4est(p4est_ghost_support_lnodes, (pforest->forest, pforest->lnodes, pforest->ghost));
1174792fecdfSBarry Smith         for (i = 1; i < overlap; i++) PetscCallP4est(p4est_ghost_expand_by_lnodes, (pforest->forest, pforest->lnodes, pforest->ghost));
11750a96aa3bSJed Brown 
11760a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
11770a96aa3bSJed Brown         cEnd                               = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
11780a96aa3bSJed Brown 
11790a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
11800a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
11819566063dSJacob Faibussowitsch           if (adaptFrom) PetscCall(DMForestGetCellSF(adaptFrom, &preCellSF));
11820a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
11839566063dSJacob Faibussowitsch           PetscCall(DMForestGetCellSF(dm, &cellSF));
11840a96aa3bSJed Brown         }
11850a96aa3bSJed Brown         if (preCoarseToFine) {
11860a96aa3bSJed Brown           PetscSF            preCoarseToFineNew;
11870a96aa3bSJed Brown           PetscInt           nleaves, nroots, *leavesNew, i, nleavesNew;
11880a96aa3bSJed Brown           const PetscInt    *leaves;
11890a96aa3bSJed Brown           const PetscSFNode *remotes;
11900a96aa3bSJed Brown           PetscSFNode       *remotesAll;
11910a96aa3bSJed Brown 
11929566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(preCoarseToFine));
11939566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCoarseToFine, &nroots, &nleaves, &leaves, &remotes));
11949566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(cEnd, &remotesAll));
11950a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
11960a96aa3bSJed Brown             remotesAll[i].rank  = -1;
11970a96aa3bSJed Brown             remotesAll[i].index = -1;
11980a96aa3bSJed Brown           }
11990a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
12009566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(cellSF));
12019566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(cellSF, MPIU_2INT, remotesAll, remotesAll, MPI_REPLACE));
12029566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(cellSF, MPIU_2INT, remotesAll, remotesAll, MPI_REPLACE));
12030a96aa3bSJed Brown           nleavesNew = 0;
12040a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12050a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
12060a96aa3bSJed Brown           }
12079566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesNew, &leavesNew));
12080a96aa3bSJed Brown           nleavesNew = 0;
12090a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12100a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
12110a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
12120a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
12130a96aa3bSJed Brown               nleavesNew++;
12140a96aa3bSJed Brown             }
12150a96aa3bSJed Brown           }
12169566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &preCoarseToFineNew));
12170a96aa3bSJed Brown           if (nleavesNew < cEnd) {
12189566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew, nroots, nleavesNew, leavesNew, PETSC_OWN_POINTER, remotesAll, PETSC_COPY_VALUES));
12190a96aa3bSJed Brown           } else { /* all cells are leaves */
12209566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
12219566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew, nroots, nleavesNew, NULL, PETSC_OWN_POINTER, remotesAll, PETSC_COPY_VALUES));
12220a96aa3bSJed Brown           }
12239566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesAll));
12249566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&preCoarseToFine));
12250a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12260a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12270a96aa3bSJed Brown         }
12280a96aa3bSJed Brown         if (coarseToPreFine) {
12290a96aa3bSJed Brown           PetscSF            coarseToPreFineNew;
12300a96aa3bSJed Brown           PetscInt           nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
12310a96aa3bSJed Brown           const PetscInt    *leaves;
12320a96aa3bSJed Brown           const PetscSFNode *remotes;
12330a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
12340a96aa3bSJed Brown 
12359566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(coarseToPreFine));
12369566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseToPreFine, &nroots, &nleaves, &leaves, &remotes));
12379566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCellSF, NULL, &nleavesCellSF, NULL, NULL));
12389566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nroots, &remotesNewRoot));
12399566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleaves, &remotesNew));
12400a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
12410a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
12420a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
12430a96aa3bSJed Brown           }
12449566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(coarseToPreFine, MPIU_2INT, remotesNewRoot, remotesNew, MPI_REPLACE));
12459566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(coarseToPreFine, MPIU_2INT, remotesNewRoot, remotesNew, MPI_REPLACE));
12469566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNewRoot));
12479566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesCellSF, &remotesExpanded));
12480a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12490a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
12500a96aa3bSJed Brown             remotesExpanded[i].index = -1;
12510a96aa3bSJed Brown           }
12520a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
12539566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNew));
12549566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(preCellSF, MPIU_2INT, remotesExpanded, remotesExpanded, MPI_REPLACE));
12559566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(preCellSF, MPIU_2INT, remotesExpanded, remotesExpanded, MPI_REPLACE));
12560a96aa3bSJed Brown 
12570a96aa3bSJed Brown           nleavesExpanded = 0;
12580a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12590a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
12600a96aa3bSJed Brown           }
12619566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesExpanded, &leavesNew));
12620a96aa3bSJed Brown           nleavesExpanded = 0;
12630a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12640a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
12650a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
12660a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
12670a96aa3bSJed Brown               nleavesExpanded++;
12680a96aa3bSJed Brown             }
12690a96aa3bSJed Brown           }
12709566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &coarseToPreFineNew));
12710a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
12729566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew, cEnd, nleavesExpanded, leavesNew, PETSC_OWN_POINTER, remotesExpanded, PETSC_COPY_VALUES));
12730a96aa3bSJed Brown           } else {
12749566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
12759566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew, cEnd, nleavesExpanded, NULL, PETSC_OWN_POINTER, remotesExpanded, PETSC_COPY_VALUES));
12760a96aa3bSJed Brown           }
12779566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesExpanded));
12789566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseToPreFine));
12790a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
12800a96aa3bSJed Brown         }
12810a96aa3bSJed Brown       }
12820a96aa3bSJed Brown     }
12830a96aa3bSJed Brown   }
12840a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
12850a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
12860a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
12879566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&ctx.anyChange, &(pforest->adaptivitySuccess), 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
12889566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, NULL));
12890a96aa3bSJed Brown   PetscFunctionReturn(0);
12900a96aa3bSJed Brown }
12910a96aa3bSJed Brown 
12920a96aa3bSJed Brown #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
12939371c9d4SSatish Balay static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success) {
12940a96aa3bSJed Brown   DM_Forest         *forest;
12950a96aa3bSJed Brown   DM_Forest_pforest *pforest;
12960a96aa3bSJed Brown 
12970a96aa3bSJed Brown   PetscFunctionBegin;
12980a96aa3bSJed Brown   forest   = (DM_Forest *)dm->data;
12990a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *)forest->data;
13000a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
13010a96aa3bSJed Brown   PetscFunctionReturn(0);
13020a96aa3bSJed Brown }
13030a96aa3bSJed Brown 
13040a96aa3bSJed Brown #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
13059371c9d4SSatish Balay static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer) {
13060a96aa3bSJed Brown   DM dm = (DM)odm;
13070a96aa3bSJed Brown 
13080a96aa3bSJed Brown   PetscFunctionBegin;
13090a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13100a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13119566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13120a96aa3bSJed Brown   switch (viewer->format) {
13130a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
13149371c9d4SSatish Balay   case PETSC_VIEWER_ASCII_INFO: {
13150a96aa3bSJed Brown     PetscInt    dim;
13160a96aa3bSJed Brown     const char *name;
13170a96aa3bSJed Brown 
13189566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
13199566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
132063a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "Forest %s in %" PetscInt_FMT " dimensions:\n", name, dim));
132163a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Forest in %" PetscInt_FMT " dimensions:\n", dim));
13220a96aa3bSJed Brown   }
13230a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
13249371c9d4SSatish Balay   case PETSC_VIEWER_LOAD_BALANCE: {
13250a96aa3bSJed Brown     DM plex;
13260a96aa3bSJed Brown 
13279566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dm, &plex));
13289566063dSJacob Faibussowitsch     PetscCall(DMView(plex, viewer));
13299371c9d4SSatish Balay   } break;
133098921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13310a96aa3bSJed Brown   }
13320a96aa3bSJed Brown   PetscFunctionReturn(0);
13330a96aa3bSJed Brown }
13340a96aa3bSJed Brown 
13350a96aa3bSJed Brown #define DMView_VTK_pforest _append_pforest(DMView_VTK)
13369371c9d4SSatish Balay static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer) {
13370a96aa3bSJed Brown   DM                 dm      = (DM)odm;
13380a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
13390a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
13400a96aa3bSJed Brown   PetscBool          isvtk;
13410a96aa3bSJed Brown   PetscReal          vtkScale = 1. - PETSC_MACHINE_EPSILON;
13420a96aa3bSJed Brown   PetscViewer_VTK   *vtk      = (PetscViewer_VTK *)viewer->data;
13430a96aa3bSJed Brown   const char        *name;
13440a96aa3bSJed Brown   char              *filenameStrip = NULL;
13450a96aa3bSJed Brown   PetscBool          hasExt;
13460a96aa3bSJed Brown   size_t             len;
13470a96aa3bSJed Brown   p4est_geometry_t  *geom;
13480a96aa3bSJed Brown 
13490a96aa3bSJed Brown   PetscFunctionBegin;
13500a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13510a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13529566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13530a96aa3bSJed Brown   geom = pforest->topo->geom;
13549566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
135528b400f6SJacob Faibussowitsch   PetscCheck(isvtk, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
13560a96aa3bSJed Brown   switch (viewer->format) {
13570a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
135828b400f6SJacob Faibussowitsch     PetscCheck(pforest->forest, PetscObjectComm(odm), PETSC_ERR_ARG_WRONG, "DM has not been setup with a valid forest");
13590a96aa3bSJed Brown     name = vtk->filename;
13609566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(name, &len));
13619566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(name + len - 4, ".vtu", &hasExt));
13620a96aa3bSJed Brown     if (hasExt) {
13639566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(name, &filenameStrip));
13640a96aa3bSJed Brown       filenameStrip[len - 4] = '\0';
13650a96aa3bSJed Brown       name                   = filenameStrip;
13660a96aa3bSJed Brown     }
1367792fecdfSBarry Smith     if (!pforest->topo->geom) PetscCallP4estReturn(geom, p4est_geometry_new_connectivity, (pforest->topo->conn));
13680a96aa3bSJed Brown     {
13690a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
13700a96aa3bSJed Brown       int                  footerr;
13710a96aa3bSJed Brown 
1372792fecdfSBarry Smith       PetscCallP4estReturn(pvtk, p4est_vtk_context_new, (pforest->forest, name));
1373792fecdfSBarry Smith       PetscCallP4est(p4est_vtk_context_set_geom, (pvtk, geom));
1374792fecdfSBarry Smith       PetscCallP4est(p4est_vtk_context_set_scale, (pvtk, (double)vtkScale));
1375792fecdfSBarry Smith       PetscCallP4estReturn(pvtk, p4est_vtk_write_header, (pvtk));
137628b400f6SJacob Faibussowitsch       PetscCheck(pvtk, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_header() failed");
13779371c9d4SSatish Balay       PetscCallP4estReturn(pvtk, p4est_vtk_write_cell_dataf,
13789371c9d4SSatish Balay                            (pvtk, 1, /* write tree */
13790a96aa3bSJed Brown                             1,       /* write level */
13800a96aa3bSJed Brown                             1,       /* write rank */
13810a96aa3bSJed Brown                             0,       /* do not wrap rank */
13820a96aa3bSJed Brown                             0,       /* no scalar fields */
13830a96aa3bSJed Brown                             0,       /* no vector fields */
13840a96aa3bSJed Brown                             pvtk));
138528b400f6SJacob Faibussowitsch       PetscCheck(pvtk, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_cell_dataf() failed");
1386792fecdfSBarry Smith       PetscCallP4estReturn(footerr, p4est_vtk_write_footer, (pvtk));
138728b400f6SJacob Faibussowitsch       PetscCheck(!footerr, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_footer() failed");
13880a96aa3bSJed Brown     }
1389792fecdfSBarry Smith     if (!pforest->topo->geom) PetscCallP4est(p4est_geometry_destroy, (geom));
13909566063dSJacob Faibussowitsch     PetscCall(PetscFree(filenameStrip));
13910a96aa3bSJed Brown     break;
139298921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13930a96aa3bSJed Brown   }
13940a96aa3bSJed Brown   PetscFunctionReturn(0);
13950a96aa3bSJed Brown }
13960a96aa3bSJed Brown 
13970a96aa3bSJed Brown #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
13989371c9d4SSatish Balay static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer) {
13990a96aa3bSJed Brown   DM plex;
14000a96aa3bSJed Brown 
14010a96aa3bSJed Brown   PetscFunctionBegin;
14029566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14039566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14049566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14050a96aa3bSJed Brown   PetscFunctionReturn(0);
14060a96aa3bSJed Brown }
14070a96aa3bSJed Brown 
14080a96aa3bSJed Brown #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
14099371c9d4SSatish Balay static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer) {
14100a96aa3bSJed Brown   DM plex;
14110a96aa3bSJed Brown 
14120a96aa3bSJed Brown   PetscFunctionBegin;
14139566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14149566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14159566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14160a96aa3bSJed Brown   PetscFunctionReturn(0);
14170a96aa3bSJed Brown }
14180a96aa3bSJed Brown 
14190a96aa3bSJed Brown #define DMView_pforest _append_pforest(DMView)
14209371c9d4SSatish Balay static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer) {
14210a96aa3bSJed Brown   PetscBool isascii, isvtk, ishdf5, isglvis;
14220a96aa3bSJed Brown 
14230a96aa3bSJed Brown   PetscFunctionBegin;
14240a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14250a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
14269566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
14279566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
14289566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
14299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
14300a96aa3bSJed Brown   if (isascii) {
14319566063dSJacob Faibussowitsch     PetscCall(DMView_ASCII_pforest((PetscObject)dm, viewer));
14320a96aa3bSJed Brown   } else if (isvtk) {
14339566063dSJacob Faibussowitsch     PetscCall(DMView_VTK_pforest((PetscObject)dm, viewer));
14340a96aa3bSJed Brown   } else if (ishdf5) {
14359566063dSJacob Faibussowitsch     PetscCall(DMView_HDF5_pforest(dm, viewer));
14360a96aa3bSJed Brown   } else if (isglvis) {
14379566063dSJacob Faibussowitsch     PetscCall(DMView_GLVis_pforest(dm, viewer));
14380a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer not supported (not VTK, HDF5, or GLVis)");
14390a96aa3bSJed Brown   PetscFunctionReturn(0);
14400a96aa3bSJed Brown }
14410a96aa3bSJed Brown 
14429371c9d4SSatish Balay static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq) {
14430a96aa3bSJed Brown   PetscInt *ttf, f, t, g, count;
14440a96aa3bSJed Brown   PetscInt  numFacets;
14450a96aa3bSJed Brown 
14460a96aa3bSJed Brown   PetscFunctionBegin;
14470a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
14489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFacets, &ttf));
14490a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
14500a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
14510a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
14520a96aa3bSJed Brown       if (ttf[g] == -1) {
14530a96aa3bSJed Brown         PetscInt ng;
14540a96aa3bSJed Brown 
14550a96aa3bSJed Brown         ttf[g]  = count++;
14560a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
14570a96aa3bSJed Brown         ttf[ng] = ttf[g];
14580a96aa3bSJed Brown       }
14590a96aa3bSJed Brown     }
14600a96aa3bSJed Brown   }
14610a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
14620a96aa3bSJed Brown   PetscFunctionReturn(0);
14630a96aa3bSJed Brown }
14640a96aa3bSJed Brown 
14659371c9d4SSatish Balay static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq) {
14660a96aa3bSJed Brown   p4est_topidx_t numTrees, numVerts, numCorns, numCtt;
14670a96aa3bSJed Brown   PetscSection   ctt;
14680a96aa3bSJed Brown #if defined(P4_TO_P8)
14690a96aa3bSJed Brown   p4est_topidx_t numEdges, numEtt;
14700a96aa3bSJed Brown   PetscSection   ett;
14710a96aa3bSJed Brown   PetscInt       eStart, eEnd, e, ettSize;
14720a96aa3bSJed Brown   PetscInt       vertOff = 1 + P4EST_FACES + P8EST_EDGES;
14730a96aa3bSJed Brown   PetscInt       edgeOff = 1 + P4EST_FACES;
14740a96aa3bSJed Brown #else
14750a96aa3bSJed Brown   PetscInt vertOff = 1 + P4EST_FACES;
14760a96aa3bSJed Brown #endif
14770a96aa3bSJed Brown   p4est_connectivity_t *conn;
14780a96aa3bSJed Brown   PetscInt              cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
14790a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
14800a96aa3bSJed Brown   PetscInt             *ttf;
14810a96aa3bSJed Brown 
14820a96aa3bSJed Brown   PetscFunctionBegin;
14830a96aa3bSJed Brown   /* 1: count objects, allocate */
14849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
14859566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cEnd - cStart, &numTrees));
14860a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
14879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
14889566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(vEnd - vStart, &numCorns));
14899566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &ctt));
14909566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ctt, vStart, vEnd));
14910a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
14920a96aa3bSJed Brown     PetscInt s;
14930a96aa3bSJed Brown 
14949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
14950a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
14960a96aa3bSJed Brown       PetscInt p = star[2 * s];
14970a96aa3bSJed Brown 
14980a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
14990a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
15000a96aa3bSJed Brown          * only protects against periodicity problems */
15019566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
150263a3b9bcSJacob Faibussowitsch         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cell %" PetscInt_FMT " with wrong closure size %" PetscInt_FMT " != %d", p, closureSize, P4EST_INSUL);
15030a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
15040a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
15050a96aa3bSJed Brown 
15061dca8a05SBarry Smith           PetscCheck(cellVert >= vStart && cellVert < vEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure: vertices");
150748a46eb9SPierre Jolivet           if (cellVert == v) PetscCall(PetscSectionAddDof(ctt, v, 1));
15080a96aa3bSJed Brown         }
15099566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
15100a96aa3bSJed Brown       }
15110a96aa3bSJed Brown     }
15129566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
15130a96aa3bSJed Brown   }
15149566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ctt));
15159566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ctt, &cttSize));
15169566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cttSize, &numCtt));
15170a96aa3bSJed Brown #if defined(P4_TO_P8)
15189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, P4EST_DIM - 1, &eStart, &eEnd));
15199566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(eEnd - eStart, &numEdges));
15209566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &ett));
15219566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ett, eStart, eEnd));
15220a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
15230a96aa3bSJed Brown     PetscInt s;
15240a96aa3bSJed Brown 
15259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
15260a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15270a96aa3bSJed Brown       PetscInt p = star[2 * s];
15280a96aa3bSJed Brown 
15290a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15300a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
15310a96aa3bSJed Brown          * only protects against periodicity problems */
15329566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
153308401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cell with wrong closure size");
15340a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
15350a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
15360a96aa3bSJed Brown 
15371dca8a05SBarry Smith           PetscCheck(cellEdge >= eStart && cellEdge < eEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure: edges");
153848a46eb9SPierre Jolivet           if (cellEdge == e) PetscCall(PetscSectionAddDof(ett, e, 1));
15390a96aa3bSJed Brown         }
15409566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
15410a96aa3bSJed Brown       }
15420a96aa3bSJed Brown     }
15439566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
15440a96aa3bSJed Brown   }
15459566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ett));
15469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ett, &ettSize));
15479566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(ettSize, &numEtt));
15480a96aa3bSJed Brown 
15490a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
1550792fecdfSBarry Smith   PetscCallP4estReturn(conn, p8est_connectivity_new, (numVerts, numTrees, numEdges, numEtt, numCorns, numCtt));
15510a96aa3bSJed Brown #else
1552792fecdfSBarry Smith   PetscCallP4estReturn(conn, p4est_connectivity_new, (numVerts, numTrees, numCorns, numCtt));
15530a96aa3bSJed Brown #endif
15540a96aa3bSJed Brown 
15550a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
15569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 1, &fStart, &fEnd));
15579566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((cEnd - cStart) * P4EST_FACES, &ttf));
15580a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
15590a96aa3bSJed Brown     PetscInt        numSupp, s;
15600a96aa3bSJed Brown     PetscInt        myFace[2] = {-1, -1};
15610a96aa3bSJed Brown     PetscInt        myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
15620a96aa3bSJed Brown     const PetscInt *supp;
15630a96aa3bSJed Brown 
15649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numSupp));
15651dca8a05SBarry Smith     PetscCheck(numSupp == 1 || numSupp == 2, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "point %" PetscInt_FMT " has facet with %" PetscInt_FMT " sides: must be 1 or 2 (boundary or conformal)", f, numSupp);
15669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &supp));
15670a96aa3bSJed Brown 
15680a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
15690a96aa3bSJed Brown       PetscInt p = supp[s];
15700a96aa3bSJed Brown 
15710a96aa3bSJed Brown       if (p >= cEnd) {
15720a96aa3bSJed Brown         numSupp--;
15730a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
15740a96aa3bSJed Brown         break;
15750a96aa3bSJed Brown       }
15760a96aa3bSJed Brown     }
15770a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
15780a96aa3bSJed Brown       PetscInt        p = supp[s], i;
15790a96aa3bSJed Brown       PetscInt        numCone;
15800a96aa3bSJed Brown       DMPolytopeType  ct;
15810a96aa3bSJed Brown       const PetscInt *cone;
15820a96aa3bSJed Brown       const PetscInt *ornt;
15830a96aa3bSJed Brown       PetscInt        orient = PETSC_MIN_INT;
15840a96aa3bSJed Brown 
15859566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &numCone));
158663a3b9bcSJacob Faibussowitsch       PetscCheck(numCone == P4EST_FACES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "cell %" PetscInt_FMT " has %" PetscInt_FMT " facets, expect %d", p, numCone, P4EST_FACES);
15879566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
15889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[0], &ct));
15899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
15900a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
15910a96aa3bSJed Brown         if (cone[i] == f) {
15920a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
15930a96aa3bSJed Brown           break;
15940a96aa3bSJed Brown         }
15950a96aa3bSJed Brown       }
159663a3b9bcSJacob Faibussowitsch       PetscCheck(i < P4EST_FACES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "cell %" PetscInt_FMT " faced %" PetscInt_FMT " mismatch", p, f);
15970a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
15980a96aa3bSJed Brown         DMPolytopeType ct;
15999566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
160063a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "cell %" PetscInt_FMT " (%s) should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")", p, DMPolytopeTypes[ct], cStart, cEnd);
16010a96aa3bSJed Brown       }
16020a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
16030a96aa3bSJed Brown       if (numSupp == 1) {
16040a96aa3bSJed Brown         /* boundary faces indicated by self reference */
16050a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
16060a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t)PetscFaceToP4estFace[i];
16070a96aa3bSJed Brown       } else {
16080a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16090a96aa3bSJed Brown 
16100a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
16110a96aa3bSJed Brown         myFace[s]                                                                = PetscFaceToP4estFace[i];
16120a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
16130a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
16140a96aa3bSJed Brown         myOrnt[s]                                                                = DihedralCompose(N, orient, DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
16150a96aa3bSJed Brown       }
16160a96aa3bSJed Brown     }
16170a96aa3bSJed Brown     if (numSupp == 2) {
16180a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
16190a96aa3bSJed Brown         PetscInt       p = supp[s];
16200a96aa3bSJed Brown         PetscInt       orntAtoB;
16210a96aa3bSJed Brown         PetscInt       p4estOrient;
16220a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16230a96aa3bSJed Brown 
16240a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
16250a96aa3bSJed Brown          * permutation of this cell-facet's cone */
16260a96aa3bSJed Brown         orntAtoB = DihedralCompose(N, DihedralInvert(N, myOrnt[1 - s]), myOrnt[s]);
16270a96aa3bSJed Brown 
16280a96aa3bSJed Brown         /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
16290a96aa3bSJed Brown          * vertices around facet) */
16300a96aa3bSJed Brown #if !defined(P4_TO_P8)
16310a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
16320a96aa3bSJed Brown #else
16330a96aa3bSJed Brown         {
16340a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
16350a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
16360a96aa3bSJed Brown 
16370a96aa3bSJed Brown           /* swap bits */
16380a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
16390a96aa3bSJed Brown         }
16400a96aa3bSJed Brown #endif
16410a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
16420a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
16430a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t)myFace[1 - s] + p4estOrient * P4EST_FACES;
16440a96aa3bSJed Brown       }
16450a96aa3bSJed Brown     }
16460a96aa3bSJed Brown   }
16470a96aa3bSJed Brown 
16480a96aa3bSJed Brown #if defined(P4_TO_P8)
16490a96aa3bSJed Brown   /* 3: visit every edge */
16500a96aa3bSJed Brown   conn->ett_offset[0] = 0;
16510a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
16520a96aa3bSJed Brown     PetscInt off, s;
16530a96aa3bSJed Brown 
16549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ett, e, &off));
16550a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t)off;
16569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
16570a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
16580a96aa3bSJed Brown       PetscInt p = star[2 * s];
16590a96aa3bSJed Brown 
16600a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
16619566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
166208401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure");
16630a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
16640a96aa3bSJed Brown           PetscInt       cellEdge = closure[2 * (c + edgeOff)];
16650a96aa3bSJed Brown           PetscInt       cellOrnt = closure[2 * (c + edgeOff) + 1];
16660a96aa3bSJed Brown           DMPolytopeType ct;
16670a96aa3bSJed Brown 
16689566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cellEdge, &ct));
16690a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
16700a96aa3bSJed Brown           if (cellEdge == e) {
16710a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
16720a96aa3bSJed Brown             PetscInt totalOrient;
16730a96aa3bSJed Brown 
16740a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
16750a96aa3bSJed Brown             totalOrient                                                = DihedralCompose(2, cellOrnt, DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
16760a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
16770a96aa3bSJed Brown             totalOrient                                                = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
16780a96aa3bSJed Brown             conn->edge_to_tree[off]                                    = (p4est_locidx_t)(p - cStart);
16790a96aa3bSJed Brown             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standart (see
16800a96aa3bSJed Brown              * p8est_connectivity.h) */
16810a96aa3bSJed Brown             conn->edge_to_edge[off++]                                  = (int8_t)p4estEdge + P8EST_EDGES * totalOrient;
16820a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
16830a96aa3bSJed Brown           }
16840a96aa3bSJed Brown         }
16859566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
16860a96aa3bSJed Brown       }
16870a96aa3bSJed Brown     }
16889566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
16890a96aa3bSJed Brown   }
16909566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ett));
16910a96aa3bSJed Brown #endif
16920a96aa3bSJed Brown 
16930a96aa3bSJed Brown   /* 4: visit every vertex */
16940a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
16950a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
16960a96aa3bSJed Brown     PetscInt off, s;
16970a96aa3bSJed Brown 
16989566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ctt, v, &off));
16990a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t)off;
17009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
17010a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17020a96aa3bSJed Brown       PetscInt p = star[2 * s];
17030a96aa3bSJed Brown 
17040a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17059566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
170608401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure");
17070a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
17080a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
17090a96aa3bSJed Brown 
17100a96aa3bSJed Brown           if (cellVert == v) {
17110a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
17120a96aa3bSJed Brown 
17130a96aa3bSJed Brown             conn->corner_to_tree[off]                                       = (p4est_locidx_t)(p - cStart);
17140a96aa3bSJed Brown             conn->corner_to_corner[off++]                                   = (int8_t)p4estVert;
17150a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
17160a96aa3bSJed Brown           }
17170a96aa3bSJed Brown         }
17189566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
17190a96aa3bSJed Brown       }
17200a96aa3bSJed Brown     }
17219566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
17220a96aa3bSJed Brown   }
17239566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ctt));
17240a96aa3bSJed Brown 
17250a96aa3bSJed Brown   /* 5: Compute the coordinates */
17260a96aa3bSJed Brown   {
17270a96aa3bSJed Brown     PetscInt coordDim;
17280a96aa3bSJed Brown 
17299566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
17306858538eSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocalSetUp(dm));
17310a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
17320a96aa3bSJed Brown       PetscInt           dof;
17336858538eSMatthew G. Knepley       PetscBool          isDG;
17340a96aa3bSJed Brown       PetscScalar       *cellCoords = NULL;
17356858538eSMatthew G. Knepley       const PetscScalar *array;
17360a96aa3bSJed Brown 
17376858538eSMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17386858538eSMatthew G. Knepley       PetscCheck(dof == P4EST_CHILDREN * coordDim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Need coordinates at the corners: (dof) %" PetscInt_FMT " != %d * %" PetscInt_FMT " (sdim)", dof, P4EST_CHILDREN, coordDim);
17390a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
17400a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
17410a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
17420a96aa3bSJed Brown 
17430a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
17440a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
17450a96aa3bSJed Brown         for (i = 0; i < 3; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
17460a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
17470a96aa3bSJed Brown       }
17486858538eSMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17490a96aa3bSJed Brown     }
17500a96aa3bSJed Brown   }
17510a96aa3bSJed Brown 
17520a96aa3bSJed Brown #if defined(P4EST_ENABLE_DEBUG)
175308401ef6SPierre Jolivet   PetscCheck(p4est_connectivity_is_valid(conn), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Plex to p4est conversion failed");
17540a96aa3bSJed Brown #endif
17550a96aa3bSJed Brown 
17560a96aa3bSJed Brown   *connOut = conn;
17570a96aa3bSJed Brown 
17580a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
17590a96aa3bSJed Brown 
17600a96aa3bSJed Brown   PetscFunctionReturn(0);
17610a96aa3bSJed Brown }
17620a96aa3bSJed Brown 
17639371c9d4SSatish Balay static PetscErrorCode locidx_to_PetscInt(sc_array_t *array) {
17640a96aa3bSJed Brown   sc_array_t *newarray;
17650a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
17660a96aa3bSJed Brown 
17670a96aa3bSJed Brown   PetscFunctionBegin;
176808401ef6SPierre Jolivet   PetscCheck(array->elem_size == sizeof(p4est_locidx_t), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong locidx size");
17690a96aa3bSJed Brown 
17700a96aa3bSJed Brown   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(0);
17710a96aa3bSJed Brown 
17720a96aa3bSJed Brown   newarray = sc_array_new_size(sizeof(PetscInt), array->elem_count);
17730a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
17740a96aa3bSJed Brown     p4est_locidx_t il = *((p4est_locidx_t *)sc_array_index(array, zz));
17750a96aa3bSJed Brown     PetscInt      *ip = (PetscInt *)sc_array_index(newarray, zz);
17760a96aa3bSJed Brown 
17770a96aa3bSJed Brown     *ip = (PetscInt)il;
17780a96aa3bSJed Brown   }
17790a96aa3bSJed Brown 
17800a96aa3bSJed Brown   sc_array_reset(array);
17810a96aa3bSJed Brown   sc_array_init_size(array, sizeof(PetscInt), count);
17820a96aa3bSJed Brown   sc_array_copy(array, newarray);
17830a96aa3bSJed Brown   sc_array_destroy(newarray);
17840a96aa3bSJed Brown   PetscFunctionReturn(0);
17850a96aa3bSJed Brown }
17860a96aa3bSJed Brown 
17879371c9d4SSatish Balay static PetscErrorCode coords_double_to_PetscScalar(sc_array_t *array, PetscInt dim) {
17880a96aa3bSJed Brown   sc_array_t *newarray;
17890a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
17900a96aa3bSJed Brown 
17910a96aa3bSJed Brown   PetscFunctionBegin;
17921dca8a05SBarry Smith   PetscCheck(array->elem_size == 3 * sizeof(double), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong coordinate size");
17930a96aa3bSJed Brown #if !defined(PETSC_USE_COMPLEX)
17940a96aa3bSJed Brown   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(0);
17950a96aa3bSJed Brown #endif
17960a96aa3bSJed Brown 
17970a96aa3bSJed Brown   newarray = sc_array_new_size(dim * sizeof(PetscScalar), array->elem_count);
17980a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
17990a96aa3bSJed Brown     int          i;
18000a96aa3bSJed Brown     double      *id = (double *)sc_array_index(array, zz);
18010a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar *)sc_array_index(newarray, zz);
18020a96aa3bSJed Brown 
18030a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
18040a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim, 3); i++) ip[i] = (PetscScalar)id[i];
18050a96aa3bSJed Brown   }
18060a96aa3bSJed Brown 
18070a96aa3bSJed Brown   sc_array_reset(array);
18080a96aa3bSJed Brown   sc_array_init_size(array, dim * sizeof(PetscScalar), count);
18090a96aa3bSJed Brown   sc_array_copy(array, newarray);
18100a96aa3bSJed Brown   sc_array_destroy(newarray);
18110a96aa3bSJed Brown   PetscFunctionReturn(0);
18120a96aa3bSJed Brown }
18130a96aa3bSJed Brown 
18149371c9d4SSatish Balay static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t *array) {
18150a96aa3bSJed Brown   sc_array_t *newarray;
18160a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18170a96aa3bSJed Brown 
18180a96aa3bSJed Brown   PetscFunctionBegin;
18191dca8a05SBarry Smith   PetscCheck(array->elem_size == 2 * sizeof(p4est_locidx_t), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong locidx size");
18200a96aa3bSJed Brown 
18210a96aa3bSJed Brown   newarray = sc_array_new_size(sizeof(PetscSFNode), array->elem_count);
18220a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18230a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t *)sc_array_index(array, zz);
18240a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode *)sc_array_index(newarray, zz);
18250a96aa3bSJed Brown 
18260a96aa3bSJed Brown     ip->rank  = (PetscInt)il[0];
18270a96aa3bSJed Brown     ip->index = (PetscInt)il[1];
18280a96aa3bSJed Brown   }
18290a96aa3bSJed Brown 
18300a96aa3bSJed Brown   sc_array_reset(array);
18310a96aa3bSJed Brown   sc_array_init_size(array, sizeof(PetscSFNode), count);
18320a96aa3bSJed Brown   sc_array_copy(array, newarray);
18330a96aa3bSJed Brown   sc_array_destroy(newarray);
18340a96aa3bSJed Brown   PetscFunctionReturn(0);
18350a96aa3bSJed Brown }
18360a96aa3bSJed Brown 
18379371c9d4SSatish Balay static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM *plex) {
18380a96aa3bSJed Brown   PetscFunctionBegin;
18390a96aa3bSJed Brown   {
18400a96aa3bSJed Brown     sc_array_t    *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
18410a96aa3bSJed Brown     sc_array_t    *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
18420a96aa3bSJed Brown     sc_array_t    *cones             = sc_array_new(sizeof(p4est_locidx_t));
18430a96aa3bSJed Brown     sc_array_t    *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
18440a96aa3bSJed Brown     sc_array_t    *coords            = sc_array_new(3 * sizeof(double));
18450a96aa3bSJed Brown     sc_array_t    *children          = sc_array_new(sizeof(p4est_locidx_t));
18460a96aa3bSJed Brown     sc_array_t    *parents           = sc_array_new(sizeof(p4est_locidx_t));
18470a96aa3bSJed Brown     sc_array_t    *childids          = sc_array_new(sizeof(p4est_locidx_t));
18480a96aa3bSJed Brown     sc_array_t    *leaves            = sc_array_new(sizeof(p4est_locidx_t));
18490a96aa3bSJed Brown     sc_array_t    *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
18500a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
18510a96aa3bSJed Brown 
1852792fecdfSBarry Smith     PetscCallP4est(p4est_get_plex_data, (p4est, P4EST_CONNECT_FULL, 0, &first_local_quad, points_per_dim, cone_sizes, cones, cone_orientations, coords, children, parents, childids, leaves, remotes));
18530a96aa3bSJed Brown 
18549566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
18559566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
18569566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
18579566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
18589566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, P4EST_DIM));
18590a96aa3bSJed Brown 
18609566063dSJacob Faibussowitsch     PetscCall(DMPlexCreate(PETSC_COMM_SELF, plex));
18619566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(*plex, P4EST_DIM));
18629566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*plex, P4EST_DIM, (PetscInt *)points_per_dim->array, (PetscInt *)cone_sizes->array, (PetscInt *)cones->array, (PetscInt *)cone_orientations->array, (PetscScalar *)coords->array));
18639566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(*plex));
18640a96aa3bSJed Brown     sc_array_destroy(points_per_dim);
18650a96aa3bSJed Brown     sc_array_destroy(cone_sizes);
18660a96aa3bSJed Brown     sc_array_destroy(cones);
18670a96aa3bSJed Brown     sc_array_destroy(cone_orientations);
18680a96aa3bSJed Brown     sc_array_destroy(coords);
18690a96aa3bSJed Brown     sc_array_destroy(children);
18700a96aa3bSJed Brown     sc_array_destroy(parents);
18710a96aa3bSJed Brown     sc_array_destroy(childids);
18720a96aa3bSJed Brown     sc_array_destroy(leaves);
18730a96aa3bSJed Brown     sc_array_destroy(remotes);
18740a96aa3bSJed Brown   }
18750a96aa3bSJed Brown   PetscFunctionReturn(0);
18760a96aa3bSJed Brown }
18770a96aa3bSJed Brown 
18780a96aa3bSJed Brown #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
18799371c9d4SSatish Balay static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB) {
18800a96aa3bSJed Brown   PetscInt coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
18810a96aa3bSJed Brown 
18820a96aa3bSJed Brown   PetscFunctionBegin;
18830a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
18840a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
18850a96aa3bSJed Brown     if (childB) *childB = childA;
18860a96aa3bSJed Brown     PetscFunctionReturn(0);
18870a96aa3bSJed Brown   }
18889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
18896aad120cSJose E. Roman   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invariant under rotation */
18900a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
18910a96aa3bSJed Brown     if (childB) *childB = childA;
18920a96aa3bSJed Brown     PetscFunctionReturn(0);
18930a96aa3bSJed Brown   }
18940a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
18959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
18960a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
18970a96aa3bSJed Brown   }
189863a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
189928b400f6SJacob Faibussowitsch   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
19000a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
19010a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
19020a96aa3bSJed Brown     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
19030a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
19040a96aa3bSJed Brown 
19059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
19069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, childA, &supp));
19070a96aa3bSJed Brown 
19080a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
19090a96aa3bSJed Brown     for (i = 0; i < size; i++) {
19100a96aa3bSJed Brown       PetscInt sParent;
19110a96aa3bSJed Brown 
19120a96aa3bSJed Brown       sA = supp[i];
19130a96aa3bSJed Brown       if (sA == parent) continue;
19149566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
19150a96aa3bSJed Brown       if (sParent == parent) break;
19160a96aa3bSJed Brown     }
191708401ef6SPierre Jolivet     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
19180a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
19190a96aa3bSJed Brown      * parentOrientB */
19209566063dSJacob Faibussowitsch     PetscCall(DMReferenceTreeGetChildSymmetry_pforest(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
19219566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
19229566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sA, &coneA));
19239566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sB, &coneB));
19249566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
19259566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
19260a96aa3bSJed Brown     /* step through the cone of sA in natural order */
19270a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
19280a96aa3bSJed Brown       if (coneA[i] == childA) {
19290a96aa3bSJed Brown         /* if childA is at position i in coneA,
19300a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
19310a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
19320a96aa3bSJed Brown         if (childB) *childB = coneB[j];
19330a96aa3bSJed Brown         if (childOrientB) {
19340a96aa3bSJed Brown           DMPolytopeType ct;
19350a96aa3bSJed Brown           PetscInt       oBtrue;
19360a96aa3bSJed Brown 
19379566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
19380a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
19391dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
19400a96aa3bSJed Brown           ct            = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
19410a96aa3bSJed Brown           /* we may have to flip an edge */
19420a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
19430a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
19440a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
19450a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
19460a96aa3bSJed Brown         }
19470a96aa3bSJed Brown         break;
19480a96aa3bSJed Brown       }
19490a96aa3bSJed Brown     }
195008401ef6SPierre Jolivet     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
19510a96aa3bSJed Brown     PetscFunctionReturn(0);
19520a96aa3bSJed Brown   }
19530a96aa3bSJed Brown   /* get the cone size and symmetry swap */
19549566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
19550a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
19560a96aa3bSJed Brown   if (dim == 2) {
19570a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
19580a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
19590a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
19600a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
19610a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
19620a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
19630a96aa3bSJed Brown   } else {
19640a96aa3bSJed Brown     oAvert     = parentOrientA;
19650a96aa3bSJed Brown     oBvert     = parentOrientB;
19660a96aa3bSJed Brown     ABswapVert = ABswap;
19670a96aa3bSJed Brown   }
19680a96aa3bSJed Brown   if (childB) {
19690a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
19700a96aa3bSJed Brown     PetscInt        p, posA = -1, numChildren, i;
19710a96aa3bSJed Brown     const PetscInt *children;
19720a96aa3bSJed Brown 
19730a96aa3bSJed Brown     /* count which position the child is in */
19749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
19750a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
19760a96aa3bSJed Brown       p = children[i];
19770a96aa3bSJed Brown       if (p == childA) {
19780a96aa3bSJed Brown         if (dim == 1) {
19790a96aa3bSJed Brown           posA = i;
19800a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
19810a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
19820a96aa3bSJed Brown         }
19830a96aa3bSJed Brown         break;
19840a96aa3bSJed Brown       }
19850a96aa3bSJed Brown     }
19860a96aa3bSJed Brown     if (posA >= coneSize) {
19870a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find childA in children of parent");
19880a96aa3bSJed Brown     } else {
19890a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
19900a96aa3bSJed Brown       PetscInt posB, childIdB;
19910a96aa3bSJed Brown 
19920a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
19930a96aa3bSJed Brown       if (dim == 1) {
19940a96aa3bSJed Brown         childIdB = posB;
19950a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
19960a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
19970a96aa3bSJed Brown       }
19980a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
19990a96aa3bSJed Brown     }
20000a96aa3bSJed Brown   }
20010a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
20020a96aa3bSJed Brown   PetscFunctionReturn(0);
20030a96aa3bSJed Brown }
20040a96aa3bSJed Brown 
20050a96aa3bSJed Brown #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
20069371c9d4SSatish Balay static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm) {
20070a96aa3bSJed Brown   p4est_connectivity_t *refcube;
20080a96aa3bSJed Brown   p4est_t              *root, *refined;
20090a96aa3bSJed Brown   DM                    dmRoot, dmRefined;
20100a96aa3bSJed Brown   DM_Plex              *mesh;
20110a96aa3bSJed Brown   PetscMPIInt           rank;
201266c0a4b5SToby Isaac #if defined(PETSC_HAVE_MPIUNI)
201366c0a4b5SToby Isaac   sc_MPI_Comm comm_self = sc_MPI_COMM_SELF;
201466c0a4b5SToby Isaac #else
201566c0a4b5SToby Isaac   MPI_Comm comm_self = PETSC_COMM_SELF;
201666c0a4b5SToby Isaac #endif
20170a96aa3bSJed Brown 
20180a96aa3bSJed Brown   PetscFunctionBegin;
2019792fecdfSBarry Smith   PetscCallP4estReturn(refcube, p4est_connectivity_new_byname, ("unit"));
20200a96aa3bSJed Brown   { /* [-1,1]^d geometry */
20210a96aa3bSJed Brown     PetscInt i, j;
20220a96aa3bSJed Brown 
20230a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
20240a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
20250a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
20260a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
20270a96aa3bSJed Brown       }
20280a96aa3bSJed Brown     }
20290a96aa3bSJed Brown   }
2030792fecdfSBarry Smith   PetscCallP4estReturn(root, p4est_new, (comm_self, refcube, 0, NULL, NULL));
2031792fecdfSBarry Smith   PetscCallP4estReturn(refined, p4est_new_ext, (comm_self, refcube, 0, 1, 1, 0, NULL, NULL));
20329566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(root, &dmRoot));
20339566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(refined, &dmRefined));
20340a96aa3bSJed Brown   {
20350a96aa3bSJed Brown #if !defined(P4_TO_P8)
20360a96aa3bSJed Brown     PetscInt nPoints   = 25;
20379371c9d4SSatish Balay     PetscInt perm[25]  = {0, 1, 2, 3, 4, 12, 8, 14, 6, 9, 15, 5, 13, 10, 7, 11, 16, 22, 20, 24, 17, 21, 18, 23, 19};
20389371c9d4SSatish Balay     PetscInt ident[25] = {0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0, 5, 6, 7, 8, 1, 2, 3, 4, 0};
20390a96aa3bSJed Brown #else
20400a96aa3bSJed Brown     PetscInt nPoints    = 125;
20419371c9d4SSatish Balay     PetscInt perm[125]  = {0,  1,  2,  3,  4,  5,  6,  7,  8,  32, 16, 36, 24, 40, 12, 17,  37,  25,  41,  9,   33,  20,  26, 42,  13,  21,  27,  43,  10,  34,  18,  38,  28,  14,  19,  39,  29,  11,  35,  22,  30, 15,
20429371c9d4SSatish Balay                            23, 31, 44, 84, 76, 92, 52, 86, 68, 94, 60, 78, 70, 96, 45, 85,  77,  93,  54,  72,  62,  74,  46, 80,  53,  87,  69,  95,  64,  82,  47,  81,  55,  73,  66,  48,  88,  56,  90,  61,  79, 71,
20439371c9d4SSatish Balay                            97, 49, 89, 58, 63, 75, 50, 57, 91, 65, 83, 51, 59, 67, 98, 106, 110, 122, 114, 120, 118, 124, 99, 111, 115, 119, 100, 107, 116, 121, 101, 117, 102, 108, 112, 123, 103, 113, 104, 109, 105};
20449371c9d4SSatish Balay     PetscInt ident[125] = {0,  0,  0,  0,  0,  0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0, 7, 7, 8,  8,  9,  9,  10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16,
20459371c9d4SSatish Balay                            16, 17, 17, 18, 18, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 23, 24, 25, 26, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 1,  2,  3,  4,  5,  6,  0};
20460a96aa3bSJed Brown 
20470a96aa3bSJed Brown #endif
20480a96aa3bSJed Brown     IS permIS;
20490a96aa3bSJed Brown     DM dmPerm;
20500a96aa3bSJed Brown 
20519566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nPoints, perm, PETSC_USE_POINTER, &permIS));
20529566063dSJacob Faibussowitsch     PetscCall(DMPlexPermute(dmRefined, permIS, &dmPerm));
20530a96aa3bSJed Brown     if (dmPerm) {
20549566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmRefined));
20550a96aa3bSJed Brown       dmRefined = dmPerm;
20560a96aa3bSJed Brown     }
20579566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
20580a96aa3bSJed Brown     {
20590a96aa3bSJed Brown       PetscInt p;
20609566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRoot, "identity"));
20619566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRefined, "identity"));
206248a46eb9SPierre Jolivet       for (p = 0; p < P4EST_INSUL; p++) PetscCall(DMSetLabelValue(dmRoot, "identity", p, p));
206348a46eb9SPierre Jolivet       for (p = 0; p < nPoints; p++) PetscCall(DMSetLabelValue(dmRefined, "identity", p, ident[p]));
20640a96aa3bSJed Brown     }
20650a96aa3bSJed Brown   }
20669566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(dmRoot, dmRefined, "identity", dm));
20670a96aa3bSJed Brown   mesh                   = (DM_Plex *)(*dm)->data;
20680a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
20699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
20700a96aa3bSJed Brown   if (rank == 0) {
20719566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRoot, NULL, "-dm_p4est_ref_root_view"));
20729566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined, NULL, "-dm_p4est_ref_refined_view"));
20739566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined, NULL, "-dm_p4est_ref_tree_view"));
20740a96aa3bSJed Brown   }
20759566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRefined));
20769566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRoot));
2077792fecdfSBarry Smith   PetscCallP4est(p4est_destroy, (refined));
2078792fecdfSBarry Smith   PetscCallP4est(p4est_destroy, (root));
2079792fecdfSBarry Smith   PetscCallP4est(p4est_connectivity_destroy, (refcube));
20800a96aa3bSJed Brown   PetscFunctionReturn(0);
20810a96aa3bSJed Brown }
20820a96aa3bSJed Brown 
20839371c9d4SSatish Balay static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB) {
20840a96aa3bSJed Brown   void     *ctx;
20850a96aa3bSJed Brown   PetscInt  num;
20860a96aa3bSJed Brown   PetscReal val;
20870a96aa3bSJed Brown 
20880a96aa3bSJed Brown   PetscFunctionBegin;
20899566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmA, &ctx));
20909566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dmB, ctx));
20919566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmA, dmB));
20929566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dmA, &num, &val));
20939566063dSJacob Faibussowitsch   PetscCall(DMSetOutputSequenceNumber(dmB, num, val));
20940a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
20959566063dSJacob Faibussowitsch     PetscCall(DMClearLocalVectors(dmB));
20969566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->localSection));
20979566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->localSection)));
20980a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
20999566063dSJacob Faibussowitsch     PetscCall(DMClearGlobalVectors(dmB));
21009566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->globalSection));
21019566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->globalSection)));
21020a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
21039566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.section));
21049566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->defaultConstraint.section)));
21053b8ba7d1SJed Brown     dmB->defaultConstraint.section = dmA->defaultConstraint.section;
21069566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.mat));
21079566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(dmB->defaultConstraint.mat)));
21083b8ba7d1SJed Brown     dmB->defaultConstraint.mat = dmA->defaultConstraint.mat;
21099566063dSJacob Faibussowitsch     if (dmA->map) PetscCall(PetscLayoutReference(dmA->map, &dmB->map));
21100a96aa3bSJed Brown   }
21110a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
21129566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->sectionSF));
21139566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&dmB->sectionSF));
21140a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
21150a96aa3bSJed Brown   }
21160a96aa3bSJed Brown   PetscFunctionReturn(0);
21170a96aa3bSJed Brown }
21180a96aa3bSJed Brown 
21190a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
21209371c9d4SSatish Balay static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm, p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF) {
21210a96aa3bSJed Brown   PetscInt     startF, endF, startC, endC, p, nLeaves;
21220a96aa3bSJed Brown   PetscSFNode *leaves;
21230a96aa3bSJed Brown   PetscSF      sf;
21240a96aa3bSJed Brown   PetscInt    *recv, *send;
21250a96aa3bSJed Brown   PetscMPIInt  tag;
21260a96aa3bSJed Brown   MPI_Request *recvReqs, *sendReqs;
21270a96aa3bSJed Brown   PetscSection section;
21280a96aa3bSJed Brown 
21290a96aa3bSJed Brown   PetscFunctionBegin;
21309566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize, p4estC->mpirank, p4estF, p4estC, &startC, &endC));
21319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2 * (endC - startC), &recv, endC - startC, &recvReqs));
21329566063dSJacob Faibussowitsch   PetscCall(PetscCommGetNewTag(comm, &tag));
21330a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
21340a96aa3bSJed Brown     recvReqs[p - startC] = MPI_REQUEST_NULL;                                        /* just in case we don't initiate a receive */
21350a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p + 1]) { /* empty coarse partition */
21360a96aa3bSJed Brown       recv[2 * (p - startC)]     = 0;
21370a96aa3bSJed Brown       recv[2 * (p - startC) + 1] = 0;
21380a96aa3bSJed Brown       continue;
21390a96aa3bSJed Brown     }
21400a96aa3bSJed Brown 
21419566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(&recv[2 * (p - startC)], 2, MPIU_INT, p, tag, comm, &recvReqs[p - startC]));
21420a96aa3bSJed Brown   }
21439566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize, p4estC->mpirank, p4estC, p4estF, &startF, &endF));
21449566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2 * (endF - startF), &send, endF - startF, &sendReqs));
21450a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
21460a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
21470a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
21480a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p + 1];
21490a96aa3bSJed Brown     PetscInt          tStart      = (PetscInt)myFineStart->p.which_tree;
21500a96aa3bSJed Brown     PetscInt          tEnd        = (PetscInt)myFineEnd->p.which_tree;
21510a96aa3bSJed Brown     PetscInt          firstCell = -1, lastCell = -1;
21520a96aa3bSJed Brown     p4est_tree_t     *treeStart = &(((p4est_tree_t *)p4estC->trees->array)[tStart]);
21530a96aa3bSJed Brown     p4est_tree_t     *treeEnd   = (size_t)tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t *)p4estC->trees->array)[tEnd]) : NULL;
21540a96aa3bSJed Brown     ssize_t           overlapIndex;
21550a96aa3bSJed Brown 
21560a96aa3bSJed Brown     sendReqs[p - startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
21570a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p + 1]) continue;
21580a96aa3bSJed Brown 
21590a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
21600a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
2161792fecdfSBarry Smith       PetscCallP4estReturn(overlapIndex, sc_array_bsearch, (&(treeStart->quadrants), myFineStart, p4est_quadrant_disjoint));
21620a96aa3bSJed Brown       if (overlapIndex < 0) {
21630a96aa3bSJed Brown         firstCell = 0;
21640a96aa3bSJed Brown       } else {
21650a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
21660a96aa3bSJed Brown       }
21670a96aa3bSJed Brown     } else {
21680a96aa3bSJed Brown       firstCell = 0;
21690a96aa3bSJed Brown     }
21700a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
2171792fecdfSBarry Smith       PetscCallP4estReturn(overlapIndex, sc_array_bsearch, (&(treeEnd->quadrants), myFineEnd, p4est_quadrant_disjoint));
21720a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
21730a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
21740a96aa3bSJed Brown       } else {
21750a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t *)treeEnd->quadrants.array)[overlapIndex]);
21760a96aa3bSJed Brown         p4est_quadrant_t  first_desc;
21770a96aa3bSJed Brown         int               equal;
21780a96aa3bSJed Brown 
2179792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_first_descendant, (container, &first_desc, P4EST_QMAXLEVEL));
2180792fecdfSBarry Smith         PetscCallP4estReturn(equal, p4est_quadrant_is_equal, (myFineEnd, &first_desc));
21810a96aa3bSJed Brown         if (equal) {
21820a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
21830a96aa3bSJed Brown         } else {
21840a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
21850a96aa3bSJed Brown         }
21860a96aa3bSJed Brown       }
21870a96aa3bSJed Brown     } else {
21880a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
21890a96aa3bSJed Brown     }
21900a96aa3bSJed Brown     send[2 * (p - startF)]     = firstCell;
21910a96aa3bSJed Brown     send[2 * (p - startF) + 1] = lastCell - firstCell;
21929566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(&send[2 * (p - startF)], 2, MPIU_INT, p, tag, comm, &sendReqs[p - startF]));
21930a96aa3bSJed Brown   }
21949566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endC - startC), recvReqs, MPI_STATUSES_IGNORE));
21959566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
21969566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, startC, endC));
21970a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
21980a96aa3bSJed Brown     PetscInt numCells = recv[2 * (p - startC) + 1];
21999566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section, p, numCells));
22000a96aa3bSJed Brown   }
22019566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
22029566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &nLeaves));
22039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nLeaves, &leaves));
22040a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22050a96aa3bSJed Brown     PetscInt firstCell = recv[2 * (p - startC)];
22060a96aa3bSJed Brown     PetscInt numCells  = recv[2 * (p - startC) + 1];
22070a96aa3bSJed Brown     PetscInt off, i;
22080a96aa3bSJed Brown 
22099566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
22100a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
22110a96aa3bSJed Brown       leaves[off + i].rank  = p;
22120a96aa3bSJed Brown       leaves[off + i].index = firstCell + i;
22130a96aa3bSJed Brown     }
22140a96aa3bSJed Brown   }
22159566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf));
22169566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, cEnd - cStart, nLeaves, NULL, PETSC_OWN_POINTER, leaves, PETSC_OWN_POINTER));
22179566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
22189566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endF - startF), sendReqs, MPI_STATUSES_IGNORE));
22199566063dSJacob Faibussowitsch   PetscCall(PetscFree2(send, sendReqs));
22209566063dSJacob Faibussowitsch   PetscCall(PetscFree2(recv, recvReqs));
22210a96aa3bSJed Brown   *coveringSF = sf;
22220a96aa3bSJed Brown   PetscFunctionReturn(0);
22230a96aa3bSJed Brown }
22240a96aa3bSJed Brown 
22250a96aa3bSJed Brown /* closure points for locally-owned cells */
22269371c9d4SSatish Balay static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints, PetscBool redirect) {
22270a96aa3bSJed Brown   PetscInt           cStart, cEnd;
22280a96aa3bSJed Brown   PetscInt           count, c;
22290a96aa3bSJed Brown   PetscMPIInt        rank;
22300a96aa3bSJed Brown   PetscInt           closureSize = -1;
22310a96aa3bSJed Brown   PetscInt          *closure     = NULL;
22320a96aa3bSJed Brown   PetscSF            pointSF;
22330a96aa3bSJed Brown   PetscInt           nleaves, nroots;
22340a96aa3bSJed Brown   const PetscInt    *ilocal;
22350a96aa3bSJed Brown   const PetscSFNode *iremote;
22360a96aa3bSJed Brown   DM                 plex;
22370a96aa3bSJed Brown   DM_Forest         *forest;
22380a96aa3bSJed Brown   DM_Forest_pforest *pforest;
22390a96aa3bSJed Brown 
22400a96aa3bSJed Brown   PetscFunctionBegin;
22410a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
22420a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
22430a96aa3bSJed Brown   cStart  = pforest->cLocalStart;
22440a96aa3bSJed Brown   cEnd    = pforest->cLocalEnd;
22459566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
22469566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &pointSF));
22479566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &ilocal, &iremote));
22480a96aa3bSJed Brown   nleaves           = PetscMax(0, nleaves);
22490a96aa3bSJed Brown   nroots            = PetscMax(0, nroots);
22500a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
22519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numClosurePoints, closurePoints));
22529566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
22530a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
22540a96aa3bSJed Brown     PetscInt i;
22559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(plex, c, PETSC_TRUE, &closureSize, &closure));
22560a96aa3bSJed Brown 
22570a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
22580a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
22590a96aa3bSJed Brown       PetscInt loc = -1;
22600a96aa3bSJed Brown 
22619566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(p, nleaves, ilocal, &loc));
22620a96aa3bSJed Brown       if (redirect && loc >= 0) {
22630a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
22640a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
22650a96aa3bSJed Brown       } else {
22660a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
22670a96aa3bSJed Brown         (*closurePoints)[count].index = p;
22680a96aa3bSJed Brown       }
22690a96aa3bSJed Brown     }
22709566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(plex, c, PETSC_TRUE, &closureSize, &closure));
22710a96aa3bSJed Brown   }
22720a96aa3bSJed Brown   PetscFunctionReturn(0);
22730a96aa3bSJed Brown }
22740a96aa3bSJed Brown 
22759371c9d4SSatish Balay static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type) {
22760a96aa3bSJed Brown   PetscMPIInt i;
22770a96aa3bSJed Brown 
22780a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
22790a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode *)a;
22800a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode *)b;
22810a96aa3bSJed Brown 
22820a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
22830a96aa3bSJed Brown   }
22840a96aa3bSJed Brown }
22850a96aa3bSJed Brown 
22869371c9d4SSatish Balay static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[]) {
22870a96aa3bSJed Brown   MPI_Comm           comm;
22880a96aa3bSJed Brown   PetscMPIInt        rank, size;
22890a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
22900a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
22910a96aa3bSJed Brown   PetscInt           numClosureIndices;
22920a96aa3bSJed Brown   PetscInt           numClosurePointsC, numClosurePointsF;
22930a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
22940a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
22950a96aa3bSJed Brown   p4est_quadrant_t **treeQuads;
22960a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
22970a96aa3bSJed Brown   MPI_Datatype       nodeType;
22980a96aa3bSJed Brown   MPI_Datatype       nodeClosureType;
22990a96aa3bSJed Brown   MPI_Op             sfNodeReduce;
23000a96aa3bSJed Brown   p4est_topidx_t     fltF, lltF, t;
23010a96aa3bSJed Brown   DM                 plexC, plexF;
23020a96aa3bSJed Brown   PetscInt           pStartF, pEndF, pStartC, pEndC;
23030a96aa3bSJed Brown   PetscBool          saveInCoarse = PETSC_FALSE;
23040a96aa3bSJed Brown   PetscBool          saveInFine   = PETSC_FALSE;
23050a96aa3bSJed Brown   PetscBool          formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
23060a96aa3bSJed Brown   PetscInt          *cids         = NULL;
23070a96aa3bSJed Brown 
23080a96aa3bSJed Brown   PetscFunctionBegin;
23090a96aa3bSJed Brown   pforestC = (DM_Forest_pforest *)((DM_Forest *)coarse->data)->data;
23100a96aa3bSJed Brown   pforestF = (DM_Forest_pforest *)((DM_Forest *)fine->data)->data;
23110a96aa3bSJed Brown   p4estC   = pforestC->forest;
23120a96aa3bSJed Brown   p4estF   = pforestF->forest;
231308401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo, PetscObjectComm((PetscObject)coarse), PETSC_ERR_ARG_INCOMP, "DM's must have the same base DM");
23140a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
23159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
23169566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
23179566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine, &plexF));
23189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF, &pStartF, &pEndF));
23199566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse, &plexC));
23209566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC, &pStartC, &pEndC));
23210a96aa3bSJed Brown   { /* check if the results have been cached */
23220a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
23230a96aa3bSJed Brown 
23249566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(coarse, &adaptCoarse));
23259566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(fine, &adaptFine));
23260a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
23270a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
23289566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestC->pointSelfToAdaptSF)));
23290a96aa3bSJed Brown         *sf = pforestC->pointSelfToAdaptSF;
23300a96aa3bSJed Brown         if (childIds) {
23319566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
23329566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids, pforestC->pointSelfToAdaptCids, pEndF - pStartF));
23330a96aa3bSJed Brown           *childIds = cids;
23340a96aa3bSJed Brown         }
23350a96aa3bSJed Brown         PetscFunctionReturn(0);
23360a96aa3bSJed Brown       } else {
23370a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
23380a96aa3bSJed Brown         formCids     = PETSC_TRUE;
23390a96aa3bSJed Brown       }
23400a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
23410a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
23429566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestF->pointAdaptToSelfSF)));
23430a96aa3bSJed Brown         *sf = pforestF->pointAdaptToSelfSF;
23440a96aa3bSJed Brown         if (childIds) {
23459566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
23469566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids, pforestF->pointAdaptToSelfCids, pEndF - pStartF));
23470a96aa3bSJed Brown           *childIds = cids;
23480a96aa3bSJed Brown         }
23490a96aa3bSJed Brown         PetscFunctionReturn(0);
23500a96aa3bSJed Brown       } else {
23510a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
23520a96aa3bSJed Brown         formCids   = PETSC_TRUE;
23530a96aa3bSJed Brown       }
23540a96aa3bSJed Brown     }
23550a96aa3bSJed Brown   }
23560a96aa3bSJed Brown 
23570a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
23580a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
23590a96aa3bSJed Brown   /* create the datatype */
23609566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(2, MPIU_INT, &nodeType));
23619566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
23629566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_create(DMPforestMaxSFNode, PETSC_FALSE, &sfNodeReduce));
23639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(numClosureIndices * 2, MPIU_INT, &nodeClosureType));
23649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeClosureType));
23650a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
23660a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
23679566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(coarse, numClosureIndices, &numClosurePointsC, &closurePointsC, PETSC_TRUE));
23689566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(fine, numClosureIndices, &numClosurePointsF, &closurePointsF, PETSC_FALSE));
23690a96aa3bSJed Brown   /* create pointers for tree lists */
23700a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
23710a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
23729566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(lltF + 1 - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts));
23730a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
23740a96aa3bSJed Brown   if (size > 1) {
23750a96aa3bSJed Brown     PetscInt p;
23760a96aa3bSJed Brown 
23770a96aa3bSJed Brown     for (p = 0; p < size; p++) {
23780a96aa3bSJed Brown       int equal;
23790a96aa3bSJed Brown 
2380792fecdfSBarry Smith       PetscCallP4estReturn(equal, p4est_quadrant_is_equal_piggy, (&p4estC->global_first_position[p], &p4estF->global_first_position[p]));
23810a96aa3bSJed Brown       if (!equal) break;
23820a96aa3bSJed Brown     }
23830a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
23840a96aa3bSJed Brown       PetscInt          cStartC, cEndC;
23850a96aa3bSJed Brown       PetscSF           coveringSF;
23860a96aa3bSJed Brown       PetscInt          nleaves;
23870a96aa3bSJed Brown       PetscInt          count;
23880a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
23890a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
23900a96aa3bSJed Brown       p4est_topidx_t    fltC = p4estC->first_local_tree;
23910a96aa3bSJed Brown       p4est_topidx_t    lltC = p4estC->last_local_tree;
23920a96aa3bSJed Brown       p4est_topidx_t    t;
23930a96aa3bSJed Brown       PetscMPIInt       blockSizes[4]   = {P4EST_DIM, 2, 1, 1};
23949371c9d4SSatish Balay       MPI_Aint          blockOffsets[4] = {offsetof(p4est_quadrant_t, x), offsetof(p4est_quadrant_t, level), offsetof(p4est_quadrant_t, pad16), offsetof(p4est_quadrant_t, p)};
23950a96aa3bSJed Brown       MPI_Datatype      blockTypes[4]   = {MPI_INT32_T, MPI_INT8_T, MPI_INT16_T, MPI_INT32_T /* p.which_tree */};
23960a96aa3bSJed Brown       MPI_Datatype      quadStruct, quadType;
23970a96aa3bSJed Brown 
23989566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC, 0, &cStartC, &cEndC));
23999566063dSJacob Faibussowitsch       PetscCall(DMPforestGetCellCoveringSF(comm, p4estC, p4estF, pforestC->cLocalStart, pforestC->cLocalEnd, &coveringSF));
24009566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coveringSF, NULL, &nleaves, NULL, NULL));
24019566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numClosureIndices * nleaves, &newClosurePointsC));
24029566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &coverQuads));
24039566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cEndC - cStartC, &coverQuadsSend));
24040a96aa3bSJed Brown       count = 0;
24050a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
24060a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t *)p4estC->trees->array)[t]);
24070a96aa3bSJed Brown         PetscInt      q;
24080a96aa3bSJed Brown 
24099566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&coverQuadsSend[count], tree->quadrants.array, tree->quadrants.elem_count * sizeof(p4est_quadrant_t)));
24100a96aa3bSJed Brown         for (q = 0; (size_t)q < tree->quadrants.elem_count; q++) coverQuadsSend[count + q].p.which_tree = t;
24110a96aa3bSJed Brown         count += tree->quadrants.elem_count;
24120a96aa3bSJed Brown       }
24130a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
24140a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
24150a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
24160a96aa3bSJed Brown        */
24179566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_struct(4, blockSizes, blockOffsets, blockTypes, &quadStruct));
24189566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_resized(quadStruct, 0, sizeof(p4est_quadrant_t), &quadType));
24199566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&quadType));
24209566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF, nodeClosureType, closurePointsC, newClosurePointsC, MPI_REPLACE));
24219566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF, quadType, coverQuadsSend, coverQuads, MPI_REPLACE));
24229566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF, nodeClosureType, closurePointsC, newClosurePointsC, MPI_REPLACE));
24239566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF, quadType, coverQuadsSend, coverQuads, MPI_REPLACE));
24249566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadStruct));
24259566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadType));
24269566063dSJacob Faibussowitsch       PetscCall(PetscFree(coverQuadsSend));
24279566063dSJacob Faibussowitsch       PetscCall(PetscFree(closurePointsC));
24289566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coveringSF));
24290a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
24300a96aa3bSJed Brown 
24310a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
24320a96aa3bSJed Brown       {
24330a96aa3bSJed Brown         PetscInt q;
24340a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
24350a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
24360a96aa3bSJed Brown           if (!treeQuadCounts[t - fltF]++) treeQuads[t - fltF] = &coverQuads[q];
24370a96aa3bSJed Brown         }
24380a96aa3bSJed Brown       }
24390a96aa3bSJed Brown     }
24400a96aa3bSJed Brown   }
24410a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
24420a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
24430a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t *)p4estC->trees->array)[t]);
24440a96aa3bSJed Brown 
24450a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
24460a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t *)tree->quadrants.array;
24470a96aa3bSJed Brown     }
24480a96aa3bSJed Brown   }
24490a96aa3bSJed Brown 
24500a96aa3bSJed Brown   {
24510a96aa3bSJed Brown     PetscInt     p;
24520a96aa3bSJed Brown     PetscInt     cLocalStartF;
24530a96aa3bSJed Brown     PetscSF      pointSF;
24540a96aa3bSJed Brown     PetscSFNode *roots;
24550a96aa3bSJed Brown     PetscInt    *rootType;
24560a96aa3bSJed Brown     DM           refTree = NULL;
24570a96aa3bSJed Brown     DMLabel      canonical;
24580a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
24590a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
24600a96aa3bSJed Brown     PetscInt     coarseOffset;
24610a96aa3bSJed Brown     PetscInt     numCoarseQuads;
24620a96aa3bSJed Brown 
24639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF - pStartF, &roots));
24649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF - pStartF, &rootType));
24659566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(fine, &pointSF));
24660a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
24670a96aa3bSJed Brown       roots[p - pStartF].rank  = -1;
24680a96aa3bSJed Brown       roots[p - pStartF].index = -1;
24690a96aa3bSJed Brown       rootType[p - pStartF]    = -1;
24700a96aa3bSJed Brown     }
24710a96aa3bSJed Brown     if (formCids) {
24720a96aa3bSJed Brown       PetscInt child;
24730a96aa3bSJed Brown 
24749566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
24750a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
24769566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF, &refTree));
24779566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(refTree, 0, PETSC_TRUE, NULL, &rootClosure));
24780a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
24799566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, child + 1, PETSC_TRUE, NULL, &childClosures[child]));
24800a96aa3bSJed Brown       }
24819566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(refTree, "canonical", &canonical));
24820a96aa3bSJed Brown     }
24830a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
24840a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
24850a96aa3bSJed Brown       p4est_tree_t     *tree         = &(((p4est_tree_t *)p4estF->trees->array)[t]);
24860a96aa3bSJed Brown       PetscInt          numFineQuads = tree->quadrants.elem_count;
24870a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads  = treeQuads[t - fltF];
24880a96aa3bSJed Brown       p4est_quadrant_t *fineQuads    = (p4est_quadrant_t *)tree->quadrants.array;
24890a96aa3bSJed Brown       PetscInt          i, coarseCount = 0;
24900a96aa3bSJed Brown       PetscInt          offset = tree->quadrants_offset;
24910a96aa3bSJed Brown       sc_array_t        coarseQuadsArray;
24920a96aa3bSJed Brown 
24930a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
2494792fecdfSBarry Smith       PetscCallP4est(sc_array_init_data, (&coarseQuadsArray, coarseQuads, sizeof(p4est_quadrant_t), (size_t)numCoarseQuads));
24950a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
24960a96aa3bSJed Brown         PetscInt          c          = i + offset;
24970a96aa3bSJed Brown         p4est_quadrant_t *quad       = &fineQuads[i];
24980a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
24990a96aa3bSJed Brown         ssize_t           disjoint   = -1;
25000a96aa3bSJed Brown 
25010a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
25020a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
2503792fecdfSBarry Smith           PetscCallP4estReturn(disjoint, p4est_quadrant_disjoint, (quadCoarse, quad));
25040a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
25050a96aa3bSJed Brown         }
250608401ef6SPierre Jolivet         PetscCheck(disjoint == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "did not find overlapping coarse quad");
25070a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
25080a96aa3bSJed Brown           if (transferIdent) {                                                                         /* find corners */
25090a96aa3bSJed Brown             PetscInt j = 0;
25100a96aa3bSJed Brown 
25110a96aa3bSJed Brown             do {
25120a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
25130a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
25140a96aa3bSJed Brown                 int              equal;
25150a96aa3bSJed Brown 
2516792fecdfSBarry Smith                 PetscCallP4est(p4est_quadrant_corner_descendant, (quad, &cornerQuad, j, quadCoarse->level));
2517792fecdfSBarry Smith                 PetscCallP4estReturn(equal, p4est_quadrant_is_equal, (&cornerQuad, quadCoarse));
25180a96aa3bSJed Brown                 if (equal) {
25190a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
25200a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
25210a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
25220a96aa3bSJed Brown 
25230a96aa3bSJed Brown                   roots[p - pStartF]    = q;
25240a96aa3bSJed Brown                   rootType[p - pStartF] = PETSC_MAX_INT;
25250a96aa3bSJed Brown                   cids[p - pStartF]     = -1;
25260a96aa3bSJed Brown                   j++;
25270a96aa3bSJed Brown                 }
25280a96aa3bSJed Brown               }
25290a96aa3bSJed Brown               coarseCount++;
25300a96aa3bSJed Brown               disjoint = 1;
25310a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
25320a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
2533792fecdfSBarry Smith                 PetscCallP4estReturn(disjoint, p4est_quadrant_disjoint, (quadCoarse, quad));
25340a96aa3bSJed Brown               }
25350a96aa3bSJed Brown             } while (!disjoint);
25360a96aa3bSJed Brown           }
25370a96aa3bSJed Brown           continue;
25380a96aa3bSJed Brown         }
25390a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
25400a96aa3bSJed Brown           PetscInt j;
25410a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
25420a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
25430a96aa3bSJed Brown 
25440a96aa3bSJed Brown             roots[p - pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
25450a96aa3bSJed Brown             rootType[p - pStartF] = PETSC_MAX_INT; /* unconditionally accept */
25460a96aa3bSJed Brown             cids[p - pStartF]     = -1;
25470a96aa3bSJed Brown           }
25480a96aa3bSJed Brown         } else {
25490a96aa3bSJed Brown           PetscInt levelDiff                 = quad->level - quadCoarse->level;
25500a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
25510a96aa3bSJed Brown 
25520a96aa3bSJed Brown           if (formCids) {
25530a96aa3bSJed Brown             PetscInt  cl;
25540a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
25550a96aa3bSJed Brown             int       cid;
25560a96aa3bSJed Brown 
255708401ef6SPierre Jolivet             PetscCheck(levelDiff <= 1, PETSC_COMM_SELF, PETSC_ERR_USER, "Recursive child ids not implemented");
2558792fecdfSBarry Smith             PetscCallP4estReturn(cid, p4est_quadrant_child_id, (quad));
25599566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(plexF, c + cLocalStartF, PETSC_TRUE, NULL, &pointClosure));
25600a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
25610a96aa3bSJed Brown               PetscInt       p      = pointClosure[2 * cl];
25620a96aa3bSJed Brown               PetscInt       point  = childClosures[cid][2 * cl];
25630a96aa3bSJed Brown               PetscInt       ornt   = childClosures[cid][2 * cl + 1];
25640a96aa3bSJed Brown               PetscInt       newcid = -1;
25650a96aa3bSJed Brown               DMPolytopeType ct;
25660a96aa3bSJed Brown 
25670a96aa3bSJed Brown               if (rootType[p - pStartF] == PETSC_MAX_INT) continue;
25689566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCellType(refTree, point, &ct));
25690a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
25700a96aa3bSJed Brown               if (!cl) {
25710a96aa3bSJed Brown                 newcid = cid + 1;
25720a96aa3bSJed Brown               } else {
25730a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
25740a96aa3bSJed Brown 
25759566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetTreeParent(refTree, point, &parent, NULL));
25760a96aa3bSJed Brown                 if (parent == point) {
25770a96aa3bSJed Brown                   newcid = -1;
25780a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
25790a96aa3bSJed Brown                   newcid = point;
25800a96aa3bSJed Brown                 } else {
25810a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
25820a96aa3bSJed Brown 
25830a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
25840a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
25859566063dSJacob Faibussowitsch                       PetscCall(DMPlexGetCellType(refTree, parent, &rct));
25860a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
25870a96aa3bSJed Brown                       break;
25880a96aa3bSJed Brown                     }
25890a96aa3bSJed Brown                   }
259008401ef6SPierre Jolivet                   PetscCheck(rcl < P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Couldn't find parent in root closure");
25919566063dSJacob Faibussowitsch                   PetscCall(DMPlexReferenceTreeGetChildSymmetry(refTree, parent, parentOrnt, ornt, point, DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]), NULL, &newcid));
25920a96aa3bSJed Brown                 }
25930a96aa3bSJed Brown               }
25940a96aa3bSJed Brown               if (newcid >= 0) {
259548a46eb9SPierre Jolivet                 if (canonical) PetscCall(DMLabelGetValue(canonical, newcid, &newcid));
25960a96aa3bSJed Brown                 proposedCids[cl] = newcid;
25970a96aa3bSJed Brown               }
25980a96aa3bSJed Brown             }
25999566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(plexF, c + cLocalStartF, PETSC_TRUE, NULL, &pointClosure));
26000a96aa3bSJed Brown           }
26019371c9d4SSatish Balay           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {
26029371c9d4SSatish Balay             {quadCoarse->x, quadCoarse->y,
26030a96aa3bSJed Brown #if defined(P4_TO_P8)
26040a96aa3bSJed Brown              quadCoarse->z
26050a96aa3bSJed Brown #endif
26069371c9d4SSatish Balay             },
26079371c9d4SSatish Balay             {0                    }
26089371c9d4SSatish Balay           };
26099371c9d4SSatish Balay           p4est_qcoord_t fineBound[2][P4EST_DIM] = {
26109371c9d4SSatish Balay             {quad->x, quad->y,
26110a96aa3bSJed Brown #if defined(P4_TO_P8)
26120a96aa3bSJed Brown              quad->z
26130a96aa3bSJed Brown #endif
26149371c9d4SSatish Balay             },
26159371c9d4SSatish Balay             {0              }
26169371c9d4SSatish Balay           };
26170a96aa3bSJed Brown           PetscInt j;
26180a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
26190a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
26200a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j] + P4EST_QUADRANT_LEN(quad->level);
26210a96aa3bSJed Brown           }
26220a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
26230a96aa3bSJed Brown             PetscInt    l, p;
26240a96aa3bSJed Brown             PetscSFNode q;
26250a96aa3bSJed Brown 
26260a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
26270a96aa3bSJed Brown             if (rootType[p - pStartF] == PETSC_MAX_INT) continue;
26280a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
26290a96aa3bSJed Brown               l = 0;
26300a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
26310a96aa3bSJed Brown               PetscInt face       = PetscFaceToP4estFace[j - 1];
26320a96aa3bSJed Brown               PetscInt direction  = face / 2;
26330a96aa3bSJed Brown               PetscInt coarseFace = -1;
26340a96aa3bSJed Brown 
26350a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
26360a96aa3bSJed Brown                 coarseFace = face;
26370a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
26380a96aa3bSJed Brown               } else {
26390a96aa3bSJed Brown                 l = 0;
26400a96aa3bSJed Brown               }
26410a96aa3bSJed Brown #if defined(P4_TO_P8)
26420a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
26430a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
26440a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
26450a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
26460a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
26470a96aa3bSJed Brown               PetscInt  minDir = PetscMin((direction + 1) % 3, (direction + 2) % 3);
26480a96aa3bSJed Brown               PetscInt  maxDir = PetscMax((direction + 1) % 3, (direction + 2) % 3);
26490a96aa3bSJed Brown               PetscBool dirTest[2];
26500a96aa3bSJed Brown 
26510a96aa3bSJed Brown               dirTest[0] = (PetscBool)(coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
26520a96aa3bSJed Brown               dirTest[1] = (PetscBool)(coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
26530a96aa3bSJed Brown 
26540a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
26550a96aa3bSJed Brown                 coarseEdge = edge;
26560a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
26570a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
26580a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
26590a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
26600a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
26610a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
26620a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
26630a96aa3bSJed Brown               } else {
26640a96aa3bSJed Brown                 l = 0;
26650a96aa3bSJed Brown               }
26660a96aa3bSJed Brown #endif
26670a96aa3bSJed Brown             } else {
26680a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
26690a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
26700a96aa3bSJed Brown               PetscInt  m;
26710a96aa3bSJed Brown               PetscInt  numMatch     = 0;
26720a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
26730a96aa3bSJed Brown #if defined(P4_TO_P8)
26740a96aa3bSJed Brown               PetscInt coarseEdge = -1;
26750a96aa3bSJed Brown #endif
26760a96aa3bSJed Brown 
26770a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
26780a96aa3bSJed Brown                 dirTest[m] = (PetscBool)(coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
26790a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
26800a96aa3bSJed Brown               }
26810a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
26820a96aa3bSJed Brown                 coarseVertex = vertex;
26830a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
26840a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
26850a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
26860a96aa3bSJed Brown                   if (dirTest[m]) {
26870a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
26880a96aa3bSJed Brown                     break;
26890a96aa3bSJed Brown                   }
26900a96aa3bSJed Brown                 }
26910a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
26920a96aa3bSJed Brown #if defined(P4_TO_P8)
26930a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
26940a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
26950a96aa3bSJed Brown                   if (!dirTest[m]) {
26960a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
26970a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
26980a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1, otherDir2);
26990a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1, otherDir2);
27000a96aa3bSJed Brown 
27010a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
27020a96aa3bSJed Brown                     break;
27030a96aa3bSJed Brown                   }
27040a96aa3bSJed Brown                 }
27050a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27060a96aa3bSJed Brown #endif
27070a96aa3bSJed Brown               } else { /* volume */
27080a96aa3bSJed Brown                 l = 0;
27090a96aa3bSJed Brown               }
27100a96aa3bSJed Brown             }
27110a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
27120a96aa3bSJed Brown             if (l > rootType[p - pStartF]) {
27130a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
27140a96aa3bSJed Brown                 if (transferIdent) {
27150a96aa3bSJed Brown                   roots[p - pStartF]    = q;
27160a96aa3bSJed Brown                   rootType[p - pStartF] = PETSC_MAX_INT;
27170a96aa3bSJed Brown                   if (formCids) cids[p - pStartF] = -1;
27180a96aa3bSJed Brown                 }
27190a96aa3bSJed Brown               } else {
27200a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
27210a96aa3bSJed Brown 
27220a96aa3bSJed Brown                 roots[p - pStartF]    = q;
27230a96aa3bSJed Brown                 rootType[p - pStartF] = l;
27240a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
27250a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
27260a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
27270a96aa3bSJed Brown                   PetscInt parent;
27280a96aa3bSJed Brown 
27299566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetTreeParent(plexF, thisp, &parent, NULL));
27300a96aa3bSJed Brown                   if (parent == thisp) break;
27310a96aa3bSJed Brown 
27320a96aa3bSJed Brown                   roots[parent - pStartF]    = q;
27330a96aa3bSJed Brown                   rootType[parent - pStartF] = PETSC_MAX_INT;
27340a96aa3bSJed Brown                   if (formCids) cids[parent - pStartF] = -1;
27350a96aa3bSJed Brown                   thisp = parent;
27360a96aa3bSJed Brown                 }
27370a96aa3bSJed Brown               }
27380a96aa3bSJed Brown             }
27390a96aa3bSJed Brown           }
27400a96aa3bSJed Brown         }
27410a96aa3bSJed Brown       }
27420a96aa3bSJed Brown     }
27430a96aa3bSJed Brown 
27440a96aa3bSJed Brown     /* now every cell has labeled the points in its closure, so we first make sure everyone agrees by reducing to roots, and the broadcast the agreements */
27450a96aa3bSJed Brown     if (size > 1) {
27460a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
27470a96aa3bSJed Brown 
27489566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &rootTypeCopy));
27499566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(rootTypeCopy, rootType, pEndF - pStartF));
275057168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_MAX));
275157168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_MAX));
27529566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_REPLACE));
27539566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_REPLACE));
27540a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
27550a96aa3bSJed Brown         if (rootTypeCopy[p - pStartF] > rootType[p - pStartF]) { /* another process found a root of higher type (e.g. vertex instead of edge), which we want to accept, so nullify this */
27560a96aa3bSJed Brown           roots[p - pStartF].rank  = -1;
27570a96aa3bSJed Brown           roots[p - pStartF].index = -1;
27580a96aa3bSJed Brown         }
27599371c9d4SSatish Balay         if (formCids && rootTypeCopy[p - pStartF] == PETSC_MAX_INT) { cids[p - pStartF] = -1; /* we have found an antecedent that is the same: no child id */ }
27600a96aa3bSJed Brown       }
27619566063dSJacob Faibussowitsch       PetscCall(PetscFree(rootTypeCopy));
27629566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF, nodeType, roots, roots, sfNodeReduce));
27639566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF, nodeType, roots, roots, sfNodeReduce));
27649566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, nodeType, roots, roots, MPI_REPLACE));
27659566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, nodeType, roots, roots, MPI_REPLACE));
27660a96aa3bSJed Brown     }
27679566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootType));
27680a96aa3bSJed Brown 
27690a96aa3bSJed Brown     {
27700a96aa3bSJed Brown       PetscInt     numRoots;
27710a96aa3bSJed Brown       PetscInt     numLeaves;
27720a96aa3bSJed Brown       PetscInt    *leaves;
27730a96aa3bSJed Brown       PetscSFNode *iremote;
27740a96aa3bSJed Brown       /* count leaves */
27750a96aa3bSJed Brown 
27760a96aa3bSJed Brown       numRoots = pEndC - pStartC;
27770a96aa3bSJed Brown 
27780a96aa3bSJed Brown       numLeaves = 0;
27790a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
27800a96aa3bSJed Brown         if (roots[p - pStartF].index >= 0) numLeaves++;
27810a96aa3bSJed Brown       }
27829566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves, &leaves));
27839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves, &iremote));
27840a96aa3bSJed Brown       numLeaves = 0;
27850a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
27860a96aa3bSJed Brown         if (roots[p - pStartF].index >= 0) {
27870a96aa3bSJed Brown           leaves[numLeaves]  = p - pStartF;
27880a96aa3bSJed Brown           iremote[numLeaves] = roots[p - pStartF];
27890a96aa3bSJed Brown           numLeaves++;
27900a96aa3bSJed Brown         }
27910a96aa3bSJed Brown       }
27929566063dSJacob Faibussowitsch       PetscCall(PetscFree(roots));
27939566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, sf));
27940a96aa3bSJed Brown       if (numLeaves == (pEndF - pStartF)) {
27959566063dSJacob Faibussowitsch         PetscCall(PetscFree(leaves));
27969566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf, numRoots, numLeaves, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
27970a96aa3bSJed Brown       } else {
27989566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf, numRoots, numLeaves, leaves, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
27990a96aa3bSJed Brown       }
28000a96aa3bSJed Brown     }
28010a96aa3bSJed Brown     if (formCids) {
28020a96aa3bSJed Brown       PetscSF  pointSF;
28030a96aa3bSJed Brown       PetscInt child;
28040a96aa3bSJed Brown 
28059566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF, &refTree));
28069566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(plexF, &pointSF));
280757168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, cids, cids, MPI_MAX));
280857168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, cids, cids, MPI_MAX));
28090a96aa3bSJed Brown       if (childIds) *childIds = cids;
281048a46eb9SPierre Jolivet       for (child = 0; child < P4EST_CHILDREN; child++) PetscCall(DMPlexRestoreTransitiveClosure(refTree, child + 1, PETSC_TRUE, NULL, &childClosures[child]));
28119566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(refTree, 0, PETSC_TRUE, NULL, &rootClosure));
28120a96aa3bSJed Brown     }
28130a96aa3bSJed Brown   }
28140a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
28159566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
28160a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
28170a96aa3bSJed Brown     if (!childIds) {
28180a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
28190a96aa3bSJed Brown     } else {
28209566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &pforestC->pointSelfToAdaptCids));
28219566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestC->pointSelfToAdaptCids, cids, pEndF - pStartF));
28220a96aa3bSJed Brown     }
28230a96aa3bSJed Brown   } else if (saveInFine) {
28249566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
28250a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
28260a96aa3bSJed Brown     if (!childIds) {
28270a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
28280a96aa3bSJed Brown     } else {
28299566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &pforestF->pointAdaptToSelfCids));
28309566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestF->pointAdaptToSelfCids, cids, pEndF - pStartF));
28310a96aa3bSJed Brown     }
28320a96aa3bSJed Brown   }
28339566063dSJacob Faibussowitsch   PetscCall(PetscFree2(treeQuads, treeQuadCounts));
28349566063dSJacob Faibussowitsch   PetscCall(PetscFree(coverQuads));
28359566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsC));
28369566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsF));
28379566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeClosureType));
28389566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_free(&sfNodeReduce));
28399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
28400a96aa3bSJed Brown   PetscFunctionReturn(0);
28410a96aa3bSJed Brown }
28420a96aa3bSJed Brown 
28430a96aa3bSJed Brown /* children are sf leaves of parents */
28449371c9d4SSatish Balay static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[]) {
28450a96aa3bSJed Brown   MPI_Comm           comm;
2846d70f29a3SPierre Jolivet   PetscMPIInt        rank;
28470a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
28480a96aa3bSJed Brown   DM                 plexC, plexF;
28490a96aa3bSJed Brown   PetscInt           pStartC, pEndC, pStartF, pEndF;
28500a96aa3bSJed Brown   PetscSF            pointTransferSF;
28510a96aa3bSJed Brown   PetscBool          allOnes = PETSC_TRUE;
28520a96aa3bSJed Brown 
28530a96aa3bSJed Brown   PetscFunctionBegin;
28540a96aa3bSJed Brown   pforestC = (DM_Forest_pforest *)((DM_Forest *)coarse->data)->data;
28550a96aa3bSJed Brown   pforestF = (DM_Forest_pforest *)((DM_Forest *)fine->data)->data;
285608401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo, PetscObjectComm((PetscObject)coarse), PETSC_ERR_ARG_INCOMP, "DM's must have the same base DM");
28570a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
28589566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
28590a96aa3bSJed Brown 
28600a96aa3bSJed Brown   {
28610a96aa3bSJed Brown     PetscInt i;
28620a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
28630a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
28640a96aa3bSJed Brown         allOnes = PETSC_FALSE;
28650a96aa3bSJed Brown         break;
28660a96aa3bSJed Brown       }
28670a96aa3bSJed Brown     }
28680a96aa3bSJed Brown   }
28699566063dSJacob Faibussowitsch   PetscCall(DMPforestGetTransferSF_Point(coarse, fine, &pointTransferSF, transferIdent, childIds));
28700a96aa3bSJed Brown   if (allOnes) {
28710a96aa3bSJed Brown     *sf = pointTransferSF;
28720a96aa3bSJed Brown     PetscFunctionReturn(0);
28730a96aa3bSJed Brown   }
28740a96aa3bSJed Brown 
28759566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine, &plexF));
28769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF, &pStartF, &pEndF));
28779566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse, &plexC));
28789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC, &pStartC, &pEndC));
28790a96aa3bSJed Brown   {
28800a96aa3bSJed Brown     PetscInt           numRoots;
28810a96aa3bSJed Brown     PetscInt           numLeaves;
28820a96aa3bSJed Brown     const PetscInt    *leaves;
28830a96aa3bSJed Brown     const PetscSFNode *iremote;
28840a96aa3bSJed Brown     PetscInt           d;
28850a96aa3bSJed Brown     PetscSection       leafSection, rootSection;
28860a96aa3bSJed Brown     /* count leaves */
28870a96aa3bSJed Brown 
28889566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointTransferSF, &numRoots, &numLeaves, &leaves, &iremote));
28899566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &rootSection));
28909566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &leafSection));
28919566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(rootSection, pStartC, pEndC));
28929566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(leafSection, pStartF, pEndF));
28930a96aa3bSJed Brown 
28940a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
28950a96aa3bSJed Brown       PetscInt startC, endC, e;
28960a96aa3bSJed Brown 
28979566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC, P4EST_DIM - d, &startC, &endC));
289848a46eb9SPierre Jolivet       for (e = startC; e < endC; e++) PetscCall(PetscSectionSetDof(rootSection, e, dofPerDim[d]));
28990a96aa3bSJed Brown     }
29000a96aa3bSJed Brown 
29010a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
29020a96aa3bSJed Brown       PetscInt startF, endF, e;
29030a96aa3bSJed Brown 
29049566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexF, P4EST_DIM - d, &startF, &endF));
290548a46eb9SPierre Jolivet       for (e = startF; e < endF; e++) PetscCall(PetscSectionSetDof(leafSection, e, dofPerDim[d]));
29060a96aa3bSJed Brown     }
29070a96aa3bSJed Brown 
29089566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(rootSection));
29099566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafSection));
29100a96aa3bSJed Brown     {
29110a96aa3bSJed Brown       PetscInt     nroots, nleaves;
29120a96aa3bSJed Brown       PetscInt    *mine, i, p;
29130a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
29140a96aa3bSJed Brown       PetscSFNode *remote;
29150a96aa3bSJed Brown 
29169566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &offsets));
29179566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndC - pStartC, &offsetsRoot));
291848a46eb9SPierre Jolivet       for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionGetOffset(rootSection, p, &offsetsRoot[p - pStartC]));
29199566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointTransferSF, MPIU_INT, offsetsRoot, offsets, MPI_REPLACE));
29209566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointTransferSF, MPIU_INT, offsetsRoot, offsets, MPI_REPLACE));
29219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(rootSection, &nroots));
29220a96aa3bSJed Brown       nleaves = 0;
29230a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
29240a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
29250a96aa3bSJed Brown         PetscInt dof;
29260a96aa3bSJed Brown 
29279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection, leaf, &dof));
29280a96aa3bSJed Brown         nleaves += dof;
29290a96aa3bSJed Brown       }
29309566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &mine));
29319566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &remote));
29320a96aa3bSJed Brown       nleaves = 0;
29330a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
29340a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
29350a96aa3bSJed Brown         PetscInt dof;
29360a96aa3bSJed Brown         PetscInt off, j;
29370a96aa3bSJed Brown 
29389566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection, leaf, &dof));
29399566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafSection, leaf, &off));
29400a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
29410a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
29420a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
29430a96aa3bSJed Brown           mine[nleaves++]       = off + j;
29440a96aa3bSJed Brown         }
29450a96aa3bSJed Brown       }
29469566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsetsRoot));
29479566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsets));
29489566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, sf));
29499566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
29500a96aa3bSJed Brown     }
29519566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
29529566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootSection));
29539566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointTransferSF));
29540a96aa3bSJed Brown   }
29550a96aa3bSJed Brown   PetscFunctionReturn(0);
29560a96aa3bSJed Brown }
29570a96aa3bSJed Brown 
29589371c9d4SSatish Balay static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA) {
29590a96aa3bSJed Brown   DM          adaptA, adaptB;
29600a96aa3bSJed Brown   DMAdaptFlag purpose;
29610a96aa3bSJed Brown 
29620a96aa3bSJed Brown   PetscFunctionBegin;
29639566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmA, &adaptA));
29649566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmB, &adaptB));
29650a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
29660a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
29679566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmA, &purpose));
29680a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
29699566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
29700a96aa3bSJed Brown       PetscFunctionReturn(0);
29710a96aa3bSJed Brown     }
29720a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
29739566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmB, &purpose));
29740a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
29759566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
29760a96aa3bSJed Brown       PetscFunctionReturn(0);
29770a96aa3bSJed Brown     }
29780a96aa3bSJed Brown   }
29791baa6e33SBarry Smith   if (sfAtoB) PetscCall(DMPforestGetTransferSF_Internal(dmA, dmB, dofPerDim, sfAtoB, PETSC_TRUE, NULL));
29801baa6e33SBarry Smith   if (sfBtoA) PetscCall(DMPforestGetTransferSF_Internal(dmB, dmA, dofPerDim, sfBtoA, (PetscBool)(sfAtoB == NULL), NULL));
29810a96aa3bSJed Brown   PetscFunctionReturn(0);
29820a96aa3bSJed Brown }
29830a96aa3bSJed Brown 
29849371c9d4SSatish Balay static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex) {
29850a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
29860a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
29870a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
29880a96aa3bSJed Brown   PetscInt           cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
29890a96aa3bSJed Brown   PetscInt           pStart, pEnd, pStartBase, pEndBase, p;
29900a96aa3bSJed Brown   DM                 base;
29910a96aa3bSJed Brown   PetscInt          *star      = NULL, starSize;
29920a96aa3bSJed Brown   DMLabelLink        next      = dm->labels;
29930a96aa3bSJed Brown   PetscInt           guess     = 0;
29940a96aa3bSJed Brown   p4est_topidx_t     num_trees = pforest->topo->conn->num_trees;
29950a96aa3bSJed Brown 
29960a96aa3bSJed Brown   PetscFunctionBegin;
29970a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
29980a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
29990a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
30009566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
30010a96aa3bSJed Brown   if (!base) {
30020a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
30030a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
30040a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
30050a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t *)p4est->trees->array;
30060a96aa3bSJed Brown       p4est_topidx_t        t, flt = p4est->first_local_tree;
30070a96aa3bSJed Brown       p4est_topidx_t        llt = pforest->forest->last_local_tree;
30080a96aa3bSJed Brown       DMLabel               ghostLabel;
30090a96aa3bSJed Brown       PetscInt              c;
30100a96aa3bSJed Brown 
30119566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(plex, pforest->ghostName));
30129566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(plex, pforest->ghostName, &ghostLabel));
30130a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
30140a96aa3bSJed Brown         p4est_tree_t     *tree     = &trees[t];
30150a96aa3bSJed Brown         p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
30160a96aa3bSJed Brown         PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
30170a96aa3bSJed Brown         PetscInt          q;
30180a96aa3bSJed Brown 
30190a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
30200a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
30210a96aa3bSJed Brown           PetscInt          f;
30220a96aa3bSJed Brown 
30230a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
30240a96aa3bSJed Brown             p4est_quadrant_t neigh;
30250a96aa3bSJed Brown             int              isOutside;
30260a96aa3bSJed Brown 
3027792fecdfSBarry Smith             PetscCallP4est(p4est_quadrant_face_neighbor, (quad, f, &neigh));
3028792fecdfSBarry Smith             PetscCallP4estReturn(isOutside, p4est_quadrant_is_outside_face, (&neigh));
30290a96aa3bSJed Brown             if (isOutside) {
30300a96aa3bSJed Brown               p4est_topidx_t nt;
30310a96aa3bSJed Brown               PetscInt       nf;
30320a96aa3bSJed Brown 
30330a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
30340a96aa3bSJed Brown               nf = (PetscInt)conn->tree_to_face[t * P4EST_FACES + f];
30350a96aa3bSJed Brown               nf = nf % P4EST_FACES;
30360a96aa3bSJed Brown               if (nt == t && nf == f) {
30370a96aa3bSJed Brown                 PetscInt        plexF = P4estFaceToPetscFace[f];
30380a96aa3bSJed Brown                 const PetscInt *cone;
30390a96aa3bSJed Brown 
30409566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetCone(plex, c, &cone));
30419566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(ghostLabel, cone[plexF], plexF + 1));
30420a96aa3bSJed Brown               }
30430a96aa3bSJed Brown             }
30440a96aa3bSJed Brown           }
30450a96aa3bSJed Brown         }
30460a96aa3bSJed Brown       }
30470a96aa3bSJed Brown     }
30480a96aa3bSJed Brown     PetscFunctionReturn(0);
30490a96aa3bSJed Brown   }
30509566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, 0, &cStartBase, &cEndBase));
30519566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, 1, &fStartBase, &fEndBase));
30529566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, P4EST_DIM - 1, &eStartBase, &eEndBase));
30539566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(base, 0, &vStartBase, &vEndBase));
30540a96aa3bSJed Brown 
30559566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd));
30569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 1, &fStart, &fEnd));
30579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, P4EST_DIM - 1, &eStart, &eEnd));
30589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
30590a96aa3bSJed Brown 
30609566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &pStart, &pEnd));
30619566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(base, &pStartBase, &pEndBase));
30620a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
30630a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
30640a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
30650a96aa3bSJed Brown   while (next) {
30660a96aa3bSJed Brown     DMLabel     baseLabel;
30670a96aa3bSJed Brown     DMLabel     label = next->label;
30680a96aa3bSJed Brown     PetscBool   isDepth, isCellType, isGhost, isVTK, isSpmap;
30690a96aa3bSJed Brown     const char *name;
30700a96aa3bSJed Brown 
30719566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)label, &name));
30729566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "depth", &isDepth));
30730a96aa3bSJed Brown     if (isDepth) {
30740a96aa3bSJed Brown       next = next->next;
30750a96aa3bSJed Brown       continue;
30760a96aa3bSJed Brown     }
30779566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "celltype", &isCellType));
30780a96aa3bSJed Brown     if (isCellType) {
30790a96aa3bSJed Brown       next = next->next;
30800a96aa3bSJed Brown       continue;
30810a96aa3bSJed Brown     }
30829566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "ghost", &isGhost));
30830a96aa3bSJed Brown     if (isGhost) {
30840a96aa3bSJed Brown       next = next->next;
30850a96aa3bSJed Brown       continue;
30860a96aa3bSJed Brown     }
30879566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "vtk", &isVTK));
30880a96aa3bSJed Brown     if (isVTK) {
30890a96aa3bSJed Brown       next = next->next;
30900a96aa3bSJed Brown       continue;
30910a96aa3bSJed Brown     }
30929566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "_forest_base_subpoint_map", &isSpmap));
30930a96aa3bSJed Brown     if (!isSpmap) {
30949566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(base, name, &baseLabel));
30950a96aa3bSJed Brown       if (!baseLabel) {
30960a96aa3bSJed Brown         next = next->next;
30970a96aa3bSJed Brown         continue;
30980a96aa3bSJed Brown       }
30999566063dSJacob Faibussowitsch       PetscCall(DMLabelCreateIndex(baseLabel, pStartBase, pEndBase));
31000a96aa3bSJed Brown     } else baseLabel = NULL;
31010a96aa3bSJed Brown 
31020a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
31030a96aa3bSJed Brown       PetscInt          s, c = -1, l;
31040a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
31050a96aa3bSJed Brown       p4est_quadrant_t *ghosts  = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
31060a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t *)pforest->forest->trees->array;
31070a96aa3bSJed Brown       p4est_quadrant_t *q;
31080a96aa3bSJed Brown       PetscInt          t, val;
31090a96aa3bSJed Brown       PetscBool         zerosupportpoint = PETSC_FALSE;
31100a96aa3bSJed Brown 
31119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
31120a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
31130a96aa3bSJed Brown         PetscInt point = star[2 * s];
31140a96aa3bSJed Brown 
31150a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
31169566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(plex, point, PETSC_TRUE, &closureSize, &closure));
31170a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
31180a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
31190a96aa3bSJed Brown             do { /* check parents of q */
31200a96aa3bSJed Brown               q = qParent;
31210a96aa3bSJed Brown               if (q == p) {
31220a96aa3bSJed Brown                 c = point;
31230a96aa3bSJed Brown                 break;
31240a96aa3bSJed Brown               }
31259566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex, q, &qParent, NULL));
31260a96aa3bSJed Brown             } while (qParent != q);
31270a96aa3bSJed Brown             if (c != -1) break;
31289566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(plex, pp, &pParent, NULL));
31290a96aa3bSJed Brown             q = closure[2 * l];
31300a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
31310a96aa3bSJed Brown               pp = pParent;
31320a96aa3bSJed Brown               if (pp == q) {
31330a96aa3bSJed Brown                 c = point;
31340a96aa3bSJed Brown                 break;
31350a96aa3bSJed Brown               }
31369566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex, pp, &pParent, NULL));
31370a96aa3bSJed Brown             }
31380a96aa3bSJed Brown             if (c != -1) break;
31390a96aa3bSJed Brown           }
31409566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(plex, point, PETSC_TRUE, NULL, &closure));
31410a96aa3bSJed Brown           if (l < closureSize) break;
31420a96aa3bSJed Brown         } else {
31430a96aa3bSJed Brown           PetscInt supportSize;
31440a96aa3bSJed Brown 
31459566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(plex, point, &supportSize));
31460a96aa3bSJed Brown           zerosupportpoint = (PetscBool)(zerosupportpoint || !supportSize);
31470a96aa3bSJed Brown         }
31480a96aa3bSJed Brown       }
31490a96aa3bSJed Brown       if (c < 0) {
31500a96aa3bSJed Brown         const char *prefix;
31510a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
31520a96aa3bSJed Brown 
31539566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
31549566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, prefix, "-dm_forest_print_label_error", &print, NULL));
31550a96aa3bSJed Brown         if (print) {
31560a96aa3bSJed Brown           PetscInt i;
31570a96aa3bSJed Brown 
315863a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF, "[%d] Failed to find cell with point %" PetscInt_FMT " in its closure for label %s (starSize %" PetscInt_FMT ")\n", PetscGlobalRank, p, baseLabel ? ((PetscObject)baseLabel)->name : "_forest_base_subpoint_map", starSize));
315963a3b9bcSJacob Faibussowitsch           for (i = 0; i < starSize; i++) PetscCall(PetscPrintf(PETSC_COMM_SELF, "  star[%" PetscInt_FMT "] = %" PetscInt_FMT ",%" PetscInt_FMT "\n", i, star[2 * i], star[2 * i + 1]));
31600a96aa3bSJed Brown         }
31619566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, NULL, &star));
31620a96aa3bSJed Brown         if (zerosupportpoint) continue;
31639371c9d4SSatish Balay         else
31649371c9d4SSatish Balay           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Failed to find cell with point %" PetscInt_FMT " in its closure for label %s. Rerun with -dm_forest_print_label_error for more information", p, baseLabel ? ((PetscObject)baseLabel)->name : "_forest_base_subpoint_map");
31650a96aa3bSJed Brown       }
31669566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, NULL, &star));
31670a96aa3bSJed Brown 
31680a96aa3bSJed Brown       if (c < cLocalStart) {
31690a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
31700a96aa3bSJed Brown         q = &(ghosts[c]);
31710a96aa3bSJed Brown         t = (PetscInt)q->p.which_tree;
31720a96aa3bSJed Brown       } else if (c < cLocalEnd) {
31730a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
31740a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
31750a96aa3bSJed Brown 
31760a96aa3bSJed Brown         c -= cLocalStart;
31770a96aa3bSJed Brown 
31780a96aa3bSJed Brown         do {
31790a96aa3bSJed Brown           p4est_tree_t *tree;
31800a96aa3bSJed Brown 
31811dca8a05SBarry Smith           PetscCheck(guess >= lo && guess < num_trees && lo < hi, PETSC_COMM_SELF, PETSC_ERR_PLIB, "failed binary search");
31820a96aa3bSJed Brown           tree = &trees[guess];
31830a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
31840a96aa3bSJed Brown             hi = guess;
31850a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt)tree->quadrants.elem_count) {
31860a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt)tree->quadrants_offset];
31870a96aa3bSJed Brown             t = guess;
31880a96aa3bSJed Brown             break;
31890a96aa3bSJed Brown           } else {
31900a96aa3bSJed Brown             lo = guess + 1;
31910a96aa3bSJed Brown           }
31920a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
31930a96aa3bSJed Brown         } while (1);
31940a96aa3bSJed Brown       } else {
31950a96aa3bSJed Brown         /* get from the end of the ghost layer */
31960a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
31970a96aa3bSJed Brown 
31980a96aa3bSJed Brown         q = &(ghosts[c]);
31990a96aa3bSJed Brown         t = (PetscInt)q->p.which_tree;
32000a96aa3bSJed Brown       }
32010a96aa3bSJed Brown 
32020a96aa3bSJed Brown       if (l == 0) { /* cell */
32030a96aa3bSJed Brown         if (baseLabel) {
32049566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32050a96aa3bSJed Brown         } else {
32060a96aa3bSJed Brown           val = t + cStartBase;
32070a96aa3bSJed Brown         }
32089566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label, p, val));
32090a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
32100a96aa3bSJed Brown         p4est_quadrant_t nq;
32110a96aa3bSJed Brown         int              isInside;
32120a96aa3bSJed Brown 
32130a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
3214792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_face_neighbor, (q, l, &nq));
3215792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
32160a96aa3bSJed Brown         if (isInside) {
32170a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
32180a96aa3bSJed Brown           if (baseLabel) {
32199566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32200a96aa3bSJed Brown           } else {
32210a96aa3bSJed Brown             val = t + cStartBase;
32220a96aa3bSJed Brown           }
32239566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32240a96aa3bSJed Brown         } else {
32250a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
32260a96aa3bSJed Brown 
32270a96aa3bSJed Brown           if (baseLabel) {
32289566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
32290a96aa3bSJed Brown           } else {
32300a96aa3bSJed Brown             val = f + fStartBase;
32310a96aa3bSJed Brown           }
32329566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32330a96aa3bSJed Brown         }
32340a96aa3bSJed Brown #if defined(P4_TO_P8)
32350a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
32360a96aa3bSJed Brown         p4est_quadrant_t nq;
32370a96aa3bSJed Brown         int              isInside;
32380a96aa3bSJed Brown 
32390a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
3240792fecdfSBarry Smith         PetscCallP4est(p8est_quadrant_edge_neighbor, (q, l, &nq));
3241792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
32420a96aa3bSJed Brown         if (isInside) {
32430a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
32440a96aa3bSJed Brown           if (baseLabel) {
32459566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32460a96aa3bSJed Brown           } else {
32470a96aa3bSJed Brown             val = t + cStartBase;
32480a96aa3bSJed Brown           }
32499566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32500a96aa3bSJed Brown         } else {
32510a96aa3bSJed Brown           int isOutsideFace;
32520a96aa3bSJed Brown 
3253792fecdfSBarry Smith           PetscCallP4estReturn(isOutsideFace, p4est_quadrant_is_outside_face, (&nq));
32540a96aa3bSJed Brown           if (isOutsideFace) {
32550a96aa3bSJed Brown             PetscInt f;
32560a96aa3bSJed Brown 
32570a96aa3bSJed Brown             if (nq.x < 0) {
32580a96aa3bSJed Brown               f = 0;
32590a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
32600a96aa3bSJed Brown               f = 1;
32610a96aa3bSJed Brown             } else if (nq.y < 0) {
32620a96aa3bSJed Brown               f = 2;
32630a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
32640a96aa3bSJed Brown               f = 3;
32650a96aa3bSJed Brown             } else if (nq.z < 0) {
32660a96aa3bSJed Brown               f = 4;
32670a96aa3bSJed Brown             } else {
32680a96aa3bSJed Brown               f = 5;
32690a96aa3bSJed Brown             }
32700a96aa3bSJed Brown             f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
32710a96aa3bSJed Brown             if (baseLabel) {
32729566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
32730a96aa3bSJed Brown             } else {
32740a96aa3bSJed Brown               val = f + fStartBase;
32750a96aa3bSJed Brown             }
32769566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
32770a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
32780a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
32790a96aa3bSJed Brown 
32800a96aa3bSJed Brown             if (baseLabel) {
32819566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, e + eStartBase, &val));
32820a96aa3bSJed Brown             } else {
32830a96aa3bSJed Brown               val = e + eStartBase;
32840a96aa3bSJed Brown             }
32859566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
32860a96aa3bSJed Brown           }
32870a96aa3bSJed Brown         }
32880a96aa3bSJed Brown #endif
32890a96aa3bSJed Brown       } else { /* vertex */
32900a96aa3bSJed Brown         p4est_quadrant_t nq;
32910a96aa3bSJed Brown         int              isInside;
32920a96aa3bSJed Brown 
32930a96aa3bSJed Brown #if defined(P4_TO_P8)
32940a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
32950a96aa3bSJed Brown #else
32960a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
32970a96aa3bSJed Brown #endif
3298792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_corner_neighbor, (q, l, &nq));
3299792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
33000a96aa3bSJed Brown         if (isInside) {
33010a96aa3bSJed Brown           if (baseLabel) {
33029566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
33030a96aa3bSJed Brown           } else {
33040a96aa3bSJed Brown             val = t + cStartBase;
33050a96aa3bSJed Brown           }
33069566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
33070a96aa3bSJed Brown         } else {
33080a96aa3bSJed Brown           int isOutside;
33090a96aa3bSJed Brown 
3310792fecdfSBarry Smith           PetscCallP4estReturn(isOutside, p4est_quadrant_is_outside_face, (&nq));
33110a96aa3bSJed Brown           if (isOutside) {
33120a96aa3bSJed Brown             PetscInt f = -1;
33130a96aa3bSJed Brown 
33140a96aa3bSJed Brown             if (nq.x < 0) {
33150a96aa3bSJed Brown               f = 0;
33160a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33170a96aa3bSJed Brown               f = 1;
33180a96aa3bSJed Brown             } else if (nq.y < 0) {
33190a96aa3bSJed Brown               f = 2;
33200a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33210a96aa3bSJed Brown               f = 3;
33220a96aa3bSJed Brown #if defined(P4_TO_P8)
33230a96aa3bSJed Brown             } else if (nq.z < 0) {
33240a96aa3bSJed Brown               f = 4;
33250a96aa3bSJed Brown             } else {
33260a96aa3bSJed Brown               f = 5;
33270a96aa3bSJed Brown #endif
33280a96aa3bSJed Brown             }
33290a96aa3bSJed Brown             f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33300a96aa3bSJed Brown             if (baseLabel) {
33319566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
33320a96aa3bSJed Brown             } else {
33330a96aa3bSJed Brown               val = f + fStartBase;
33340a96aa3bSJed Brown             }
33359566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33360a96aa3bSJed Brown             continue;
33370a96aa3bSJed Brown           }
33380a96aa3bSJed Brown #if defined(P4_TO_P8)
3339792fecdfSBarry Smith           PetscCallP4estReturn(isOutside, p8est_quadrant_is_outside_edge, (&nq));
33400a96aa3bSJed Brown           if (isOutside) {
33410a96aa3bSJed Brown             /* outside edge */
33420a96aa3bSJed Brown             PetscInt e = -1;
33430a96aa3bSJed Brown 
33440a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
33450a96aa3bSJed Brown               if (nq.z < 0) {
33460a96aa3bSJed Brown                 if (nq.y < 0) {
33470a96aa3bSJed Brown                   e = 0;
33480a96aa3bSJed Brown                 } else {
33490a96aa3bSJed Brown                   e = 1;
33500a96aa3bSJed Brown                 }
33510a96aa3bSJed Brown               } else {
33520a96aa3bSJed Brown                 if (nq.y < 0) {
33530a96aa3bSJed Brown                   e = 2;
33540a96aa3bSJed Brown                 } else {
33550a96aa3bSJed Brown                   e = 3;
33560a96aa3bSJed Brown                 }
33570a96aa3bSJed Brown               }
33580a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
33590a96aa3bSJed Brown               if (nq.z < 0) {
33600a96aa3bSJed Brown                 if (nq.x < 0) {
33610a96aa3bSJed Brown                   e = 4;
33620a96aa3bSJed Brown                 } else {
33630a96aa3bSJed Brown                   e = 5;
33640a96aa3bSJed Brown                 }
33650a96aa3bSJed Brown               } else {
33660a96aa3bSJed Brown                 if (nq.x < 0) {
33670a96aa3bSJed Brown                   e = 6;
33680a96aa3bSJed Brown                 } else {
33690a96aa3bSJed Brown                   e = 7;
33700a96aa3bSJed Brown                 }
33710a96aa3bSJed Brown               }
33720a96aa3bSJed Brown             } else {
33730a96aa3bSJed Brown               if (nq.y < 0) {
33740a96aa3bSJed Brown                 if (nq.x < 0) {
33750a96aa3bSJed Brown                   e = 8;
33760a96aa3bSJed Brown                 } else {
33770a96aa3bSJed Brown                   e = 9;
33780a96aa3bSJed Brown                 }
33790a96aa3bSJed Brown               } else {
33800a96aa3bSJed Brown                 if (nq.x < 0) {
33810a96aa3bSJed Brown                   e = 10;
33820a96aa3bSJed Brown                 } else {
33830a96aa3bSJed Brown                   e = 11;
33840a96aa3bSJed Brown                 }
33850a96aa3bSJed Brown               }
33860a96aa3bSJed Brown             }
33870a96aa3bSJed Brown 
33880a96aa3bSJed Brown             e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
33890a96aa3bSJed Brown             if (baseLabel) {
33909566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, e + eStartBase, &val));
33910a96aa3bSJed Brown             } else {
33920a96aa3bSJed Brown               val = e + eStartBase;
33930a96aa3bSJed Brown             }
33949566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33950a96aa3bSJed Brown             continue;
33960a96aa3bSJed Brown           }
33970a96aa3bSJed Brown #endif
33980a96aa3bSJed Brown           {
33990a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
34000a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
34010a96aa3bSJed Brown 
34020a96aa3bSJed Brown             if (baseLabel) {
34039566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, v + vStartBase, &val));
34040a96aa3bSJed Brown             } else {
34050a96aa3bSJed Brown               val = v + vStartBase;
34060a96aa3bSJed Brown             }
34079566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
34080a96aa3bSJed Brown           }
34090a96aa3bSJed Brown         }
34100a96aa3bSJed Brown       }
34110a96aa3bSJed Brown     }
34120a96aa3bSJed Brown     next = next->next;
34130a96aa3bSJed Brown   }
34140a96aa3bSJed Brown   PetscFunctionReturn(0);
34150a96aa3bSJed Brown }
34160a96aa3bSJed Brown 
34179371c9d4SSatish Balay static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex) {
34180a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
34190a96aa3bSJed Brown   DM                 adapt;
34200a96aa3bSJed Brown 
34210a96aa3bSJed Brown   PetscFunctionBegin;
34220a96aa3bSJed Brown   if (pforest->labelsFinalized) PetscFunctionReturn(0);
34230a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
34249566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
34250a96aa3bSJed Brown   if (!adapt) {
34260a96aa3bSJed Brown     /* Initialize labels from the base dm */
34279566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsInitialize(dm, plex));
34280a96aa3bSJed Brown   } else {
34290a96aa3bSJed Brown     PetscInt    dofPerDim[4] = {1, 1, 1, 1};
34300a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
34310a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
34320a96aa3bSJed Brown     PetscInt   *values, *adaptValues;
34330a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
34340a96aa3bSJed Brown     DMLabel     adaptLabel;
34350a96aa3bSJed Brown     DM          adaptPlex;
34360a96aa3bSJed Brown 
34379566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm, &adaptLabel));
34389566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(adapt, &adaptPlex));
34399566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF(adapt, dm, dofPerDim, &transferForward, &transferBackward));
34409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &pStart, &pEnd));
34419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(adaptPlex, &pStartA, &pEndA));
34429566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEnd - pStart, &values, pEndA - pStartA, &adaptValues));
34439566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex, &pointSF));
34440a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
34450a96aa3bSJed Brown       PetscInt p;
34460a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p - pStartA] = -1;
34470a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p - pStart] = -2;
34480a96aa3bSJed Brown       if (transferForward) {
34499566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
34509566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
34510a96aa3bSJed Brown       }
34520a96aa3bSJed Brown       if (transferBackward) {
345357168dbeSPierre Jolivet         PetscCall(PetscSFReduceBegin(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
345457168dbeSPierre Jolivet         PetscCall(PetscSFReduceEnd(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
34550a96aa3bSJed Brown       }
34560a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
34570a96aa3bSJed Brown         PetscInt q = p, parent;
34580a96aa3bSJed Brown 
34599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
34600a96aa3bSJed Brown         while (parent != q) {
34610a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
34620a96aa3bSJed Brown           q = parent;
34639566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
34640a96aa3bSJed Brown         }
34650a96aa3bSJed Brown       }
346657168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, values, values, MPI_MAX));
346757168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, values, values, MPI_MAX));
34689566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, values, values, MPI_REPLACE));
34699566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, values, values, MPI_REPLACE));
3470ad540459SPierre Jolivet       for (p = pStart; p < pEnd; p++) PetscCheck(values[p - pStart] != -2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "uncovered point %" PetscInt_FMT, p);
34710a96aa3bSJed Brown     }
34720a96aa3bSJed Brown     while (next) {
34730a96aa3bSJed Brown       DMLabel     nextLabel = next->label;
34740a96aa3bSJed Brown       const char *name;
34750a96aa3bSJed Brown       PetscBool   isDepth, isCellType, isGhost, isVTK;
34760a96aa3bSJed Brown       DMLabel     label;
34770a96aa3bSJed Brown       PetscInt    p;
34780a96aa3bSJed Brown 
34799566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)nextLabel, &name));
34809566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isDepth));
34810a96aa3bSJed Brown       if (isDepth) {
34820a96aa3bSJed Brown         next = next->next;
34830a96aa3bSJed Brown         continue;
34840a96aa3bSJed Brown       }
34859566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "celltype", &isCellType));
34860a96aa3bSJed Brown       if (isCellType) {
34870a96aa3bSJed Brown         next = next->next;
34880a96aa3bSJed Brown         continue;
34890a96aa3bSJed Brown       }
34909566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "ghost", &isGhost));
34910a96aa3bSJed Brown       if (isGhost) {
34920a96aa3bSJed Brown         next = next->next;
34930a96aa3bSJed Brown         continue;
34940a96aa3bSJed Brown       }
34959566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "vtk", &isVTK));
34960a96aa3bSJed Brown       if (isVTK) {
34970a96aa3bSJed Brown         next = next->next;
34980a96aa3bSJed Brown         continue;
34990a96aa3bSJed Brown       }
35000a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
35010a96aa3bSJed Brown         next = next->next;
35020a96aa3bSJed Brown         continue;
35030a96aa3bSJed Brown       }
35040a96aa3bSJed Brown       /* label was created earlier */
35059566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
350648a46eb9SPierre Jolivet       for (p = pStartA; p < pEndA; p++) PetscCall(DMLabelGetValue(nextLabel, p, &adaptValues[p]));
35070a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
35080a96aa3bSJed Brown 
35091baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastBegin(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
351057168dbeSPierre Jolivet       if (transferBackward) PetscCall(PetscSFReduceBegin(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35111baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastEnd(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
351257168dbeSPierre Jolivet       if (transferBackward) PetscCall(PetscSFReduceEnd(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35130a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35140a96aa3bSJed Brown         PetscInt q = p, parent;
35150a96aa3bSJed Brown 
35169566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35170a96aa3bSJed Brown         while (parent != q) {
35180a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
35190a96aa3bSJed Brown           q = parent;
35209566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35210a96aa3bSJed Brown         }
35220a96aa3bSJed Brown       }
352357168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, values, values, MPI_MAX));
352457168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, values, values, MPI_MAX));
35259566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35269566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35270a96aa3bSJed Brown 
352848a46eb9SPierre Jolivet       for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(label, p, values[p]));
35290a96aa3bSJed Brown       next = next->next;
35300a96aa3bSJed Brown     }
35319566063dSJacob Faibussowitsch     PetscCall(PetscFree2(values, adaptValues));
35329566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferForward));
35339566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferBackward));
35340a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
35350a96aa3bSJed Brown   }
35360a96aa3bSJed Brown   PetscFunctionReturn(0);
35370a96aa3bSJed Brown }
35380a96aa3bSJed Brown 
35399371c9d4SSatish Balay static PetscErrorCode DMPforestMapCoordinates_Cell(DM plex, p4est_geometry_t *geom, PetscInt cell, p4est_quadrant_t *q, p4est_topidx_t t, p4est_connectivity_t *conn, PetscScalar *coords) {
35400a96aa3bSJed Brown   PetscInt     closureSize, c, coordStart, coordEnd, coordDim;
35410a96aa3bSJed Brown   PetscInt    *closure = NULL;
35420a96aa3bSJed Brown   PetscSection coordSec;
35430a96aa3bSJed Brown 
35440a96aa3bSJed Brown   PetscFunctionBegin;
35459566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &coordSec));
35469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSec, &coordStart, &coordEnd));
35479566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(plex, &coordDim));
35489566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(plex, cell, PETSC_TRUE, &closureSize, &closure));
35490a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
35500a96aa3bSJed Brown     PetscInt point = closure[2 * c];
35510a96aa3bSJed Brown 
35520a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
35530a96aa3bSJed Brown       PetscInt dof, off;
35540a96aa3bSJed Brown       PetscInt nCoords, i;
35559566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec, point, &dof));
355608401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not understand coordinate layout");
35570a96aa3bSJed Brown       nCoords = dof / coordDim;
35589566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec, point, &off));
35590a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
35600a96aa3bSJed Brown         PetscScalar *coord               = &coords[off + i * coordDim];
35610a96aa3bSJed Brown         double       coordP4est[3]       = {0.};
35620a96aa3bSJed Brown         double       coordP4estMapped[3] = {0.};
35630a96aa3bSJed Brown         PetscInt     j;
35640a96aa3bSJed Brown         PetscReal    treeCoords[P4EST_CHILDREN][3] = {{0.}};
35650a96aa3bSJed Brown         PetscReal    eta[3]                        = {0.};
35660a96aa3bSJed Brown         PetscInt     numRounds                     = 10;
35670a96aa3bSJed Brown         PetscReal    coordGuess[3]                 = {0.};
35680a96aa3bSJed Brown 
35690a96aa3bSJed Brown         eta[0] = (PetscReal)q->x / (PetscReal)P4EST_ROOT_LEN;
35700a96aa3bSJed Brown         eta[1] = (PetscReal)q->y / (PetscReal)P4EST_ROOT_LEN;
35710a96aa3bSJed Brown #if defined(P4_TO_P8)
35720a96aa3bSJed Brown         eta[2] = (PetscReal)q->z / (PetscReal)P4EST_ROOT_LEN;
35730a96aa3bSJed Brown #endif
35740a96aa3bSJed Brown 
35750a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
35760a96aa3bSJed Brown           PetscInt k;
35770a96aa3bSJed Brown 
35780a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
35790a96aa3bSJed Brown         }
35800a96aa3bSJed Brown 
35810a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
35820a96aa3bSJed Brown           PetscInt  k;
35830a96aa3bSJed Brown           PetscReal prod = 1.;
35840a96aa3bSJed Brown 
35850a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
35860a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
35870a96aa3bSJed Brown         }
35880a96aa3bSJed Brown 
35890a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
35900a96aa3bSJed Brown           PetscInt dir;
35910a96aa3bSJed Brown 
35920a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
35930a96aa3bSJed Brown             PetscInt  k;
35940a96aa3bSJed Brown             PetscReal diff[3];
35950a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
35960a96aa3bSJed Brown             PetscReal rhs, scale, update;
35970a96aa3bSJed Brown 
35980a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
35990a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
36000a96aa3bSJed Brown               PetscInt  l;
36010a96aa3bSJed Brown               PetscReal prod = 1.;
36020a96aa3bSJed Brown 
36030a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
36040a96aa3bSJed Brown                 if (l == dir) {
36050a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? 1. : -1.;
36060a96aa3bSJed Brown                 } else {
36070a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
36080a96aa3bSJed Brown                 }
36090a96aa3bSJed Brown               }
36100a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
36110a96aa3bSJed Brown             }
36120a96aa3bSJed Brown             rhs   = 0.;
36130a96aa3bSJed Brown             scale = 0;
36140a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
36150a96aa3bSJed Brown               rhs += diff[k] * dXdeta[k];
36160a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
36170a96aa3bSJed Brown             }
36180a96aa3bSJed Brown             update = rhs / scale;
36190a96aa3bSJed Brown             eta[dir] += update;
36200a96aa3bSJed Brown             eta[dir] = PetscMin(eta[dir], 1.);
36210a96aa3bSJed Brown             eta[dir] = PetscMax(eta[dir], 0.);
36220a96aa3bSJed Brown 
36230a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
36240a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
36250a96aa3bSJed Brown               PetscInt  l;
36260a96aa3bSJed Brown               PetscReal prod = 1.;
36270a96aa3bSJed Brown 
36280a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
36290a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
36300a96aa3bSJed Brown             }
36310a96aa3bSJed Brown           }
36320a96aa3bSJed Brown         }
36330a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double)eta[j];
36340a96aa3bSJed Brown 
36350a96aa3bSJed Brown         if (geom) {
36360a96aa3bSJed Brown           (geom->X)(geom, t, coordP4est, coordP4estMapped);
36370a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar)coordP4estMapped[j];
36380a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not coded");
36390a96aa3bSJed Brown       }
36400a96aa3bSJed Brown     }
36410a96aa3bSJed Brown   }
36429566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(plex, cell, PETSC_TRUE, &closureSize, &closure));
36430a96aa3bSJed Brown   PetscFunctionReturn(0);
36440a96aa3bSJed Brown }
36450a96aa3bSJed Brown 
36469371c9d4SSatish Balay static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex) {
36470a96aa3bSJed Brown   DM_Forest         *forest;
36480a96aa3bSJed Brown   DM_Forest_pforest *pforest;
36490a96aa3bSJed Brown   p4est_geometry_t  *geom;
36500a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd;
36510a96aa3bSJed Brown   Vec                coordLocalVec;
36520a96aa3bSJed Brown   PetscScalar       *coords;
36530a96aa3bSJed Brown   p4est_topidx_t     flt, llt, t;
36540a96aa3bSJed Brown   p4est_tree_t      *trees;
36550a96aa3bSJed Brown   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
36560a96aa3bSJed Brown   void *mapCtx;
36570a96aa3bSJed Brown 
36580a96aa3bSJed Brown   PetscFunctionBegin;
36590a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
36600a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
36610a96aa3bSJed Brown   geom    = pforest->topo->geom;
36629566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
36630a96aa3bSJed Brown   if (!geom && !map) PetscFunctionReturn(0);
36649566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex, &coordLocalVec));
36659566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordLocalVec, &coords));
36660a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
36670a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
36680a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
36690a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
36700a96aa3bSJed Brown   trees       = (p4est_tree_t *)pforest->forest->trees->array;
36710a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
36720a96aa3bSJed Brown     PetscSection coordSec;
36730a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
36740a96aa3bSJed Brown     DM           base;
36750a96aa3bSJed Brown 
36769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
36779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(plex, &cEndInterior, NULL));
36780a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
36799566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm, &base));
36809566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(plex, &coordSec));
36819566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(coordSec, &coordStart, &coordEnd));
36829566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(plex, &coordDim));
36830a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim, 3);
36840a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
36850a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
36860a96aa3bSJed Brown       PetscInt  dof, off, cell = -1, coarsePoint = -1;
36870a96aa3bSJed Brown       PetscInt  nCoords, i;
36889566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec, p, &dof));
368908401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not understand coordinate layout");
36900a96aa3bSJed Brown       nCoords = dof / coordDim;
36919566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec, p, &off));
36929566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
36930a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
36940a96aa3bSJed Brown         PetscInt point = star[2 * i];
36950a96aa3bSJed Brown 
36960a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
36970a96aa3bSJed Brown           cell = point;
36980a96aa3bSJed Brown           break;
36990a96aa3bSJed Brown         }
37000a96aa3bSJed Brown       }
37019566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
37020a96aa3bSJed Brown       if (cell >= 0) {
37030a96aa3bSJed Brown         if (cell < cLocalStart) {
37040a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37050a96aa3bSJed Brown 
37060a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
37070a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
37080a96aa3bSJed Brown           cell -= cLocalStart;
37090a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
37100a96aa3bSJed Brown             p4est_tree_t *tree = &(trees[t]);
37110a96aa3bSJed Brown 
37120a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t)cell < tree->quadrants_offset + tree->quadrants.elem_count) {
37130a96aa3bSJed Brown               coarsePoint = t;
37140a96aa3bSJed Brown               break;
37150a96aa3bSJed Brown             }
37160a96aa3bSJed Brown           }
37170a96aa3bSJed Brown         } else {
37180a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37190a96aa3bSJed Brown 
37200a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
37210a96aa3bSJed Brown         }
37220a96aa3bSJed Brown       }
37230a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
37240a96aa3bSJed Brown         PetscScalar *coord               = &coords[off + i * coordDim];
37250a96aa3bSJed Brown         PetscReal    coordP4est[3]       = {0.};
37260a96aa3bSJed Brown         PetscReal    coordP4estMapped[3] = {0.};
37270a96aa3bSJed Brown         PetscInt     j;
37280a96aa3bSJed Brown 
37290a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
37309566063dSJacob Faibussowitsch         PetscCall((map)(base, coarsePoint, p4estCoordDim, coordP4est, coordP4estMapped, mapCtx));
37310a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar)coordP4estMapped[j];
37320a96aa3bSJed Brown       }
37330a96aa3bSJed Brown     }
37340a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
37350a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
37360a96aa3bSJed Brown 
37379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
37389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(plex, &cEndInterior, NULL));
37390a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
37400a96aa3bSJed Brown     if (cLocalStart > 0) {
37410a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37420a96aa3bSJed Brown       PetscInt          count;
37430a96aa3bSJed Brown 
37440a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
37450a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
37460a96aa3bSJed Brown         p4est_topidx_t    t    = quad->p.which_tree;
37470a96aa3bSJed Brown 
37489566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count, quad, t, pforest->topo->conn, coords));
37490a96aa3bSJed Brown       }
37500a96aa3bSJed Brown     }
37510a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
37520a96aa3bSJed Brown       p4est_tree_t     *tree     = &(trees[t]);
37530a96aa3bSJed Brown       PetscInt          offset   = cLocalStart + tree->quadrants_offset, i;
37540a96aa3bSJed Brown       PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
37550a96aa3bSJed Brown       p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
37560a96aa3bSJed Brown 
37570a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
37580a96aa3bSJed Brown         PetscInt count = i + offset;
37590a96aa3bSJed Brown 
37609566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count, &quads[i], t, pforest->topo->conn, coords));
37610a96aa3bSJed Brown       }
37620a96aa3bSJed Brown     }
37630a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
37640a96aa3bSJed Brown       p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37650a96aa3bSJed Brown       PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
37660a96aa3bSJed Brown       PetscInt          count;
37670a96aa3bSJed Brown 
37680a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
37690a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
37700a96aa3bSJed Brown         p4est_topidx_t    t    = quad->p.which_tree;
37710a96aa3bSJed Brown 
37729566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count + cLocalEnd, quad, t, pforest->topo->conn, coords));
37730a96aa3bSJed Brown       }
37740a96aa3bSJed Brown     }
37750a96aa3bSJed Brown   }
37769566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordLocalVec, &coords));
37770a96aa3bSJed Brown   PetscFunctionReturn(0);
37780a96aa3bSJed Brown }
37790a96aa3bSJed Brown 
37809371c9d4SSatish Balay static PetscErrorCode PforestQuadrantIsInterior(p4est_quadrant_t *quad, PetscBool *is_interior) {
3781852b71a7SToby Isaac   PetscFunctionBegin;
3782852b71a7SToby Isaac   p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3783852b71a7SToby Isaac   if ((quad->x > 0) && (quad->x + h < P4EST_ROOT_LEN)
3784852b71a7SToby Isaac #ifdef P4_TO_P8
3785852b71a7SToby Isaac       && (quad->z > 0) && (quad->z + h < P4EST_ROOT_LEN)
3786852b71a7SToby Isaac #endif
3787852b71a7SToby Isaac       && (quad->y > 0) && (quad->y + h < P4EST_ROOT_LEN)) {
3788852b71a7SToby Isaac     *is_interior = PETSC_TRUE;
3789852b71a7SToby Isaac   } else {
3790852b71a7SToby Isaac     *is_interior = PETSC_FALSE;
3791852b71a7SToby Isaac   }
3792852b71a7SToby Isaac   PetscFunctionReturn(0);
3793852b71a7SToby Isaac }
3794852b71a7SToby Isaac 
3795852b71a7SToby Isaac /* We always use DG coordinates with p4est: if they do not match the vertex
3796852b71a7SToby Isaac    coordinates, add space for them in the section */
37979371c9d4SSatish Balay static PetscErrorCode PforestCheckLocalizeCell(DM plex, PetscInt cDim, Vec cVecOld, DM_Forest_pforest *pforest, PetscSection oldSection, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad) {
3798852b71a7SToby Isaac   PetscBool is_interior;
3799852b71a7SToby Isaac 
3800852b71a7SToby Isaac   PetscFunctionBegin;
3801852b71a7SToby Isaac   PetscCall(PforestQuadrantIsInterior(quad, &is_interior));
3802852b71a7SToby Isaac   if (is_interior) { // quads in the interior of a coarse cell can't touch periodic interfaces
3803852b71a7SToby Isaac     PetscCall(PetscSectionSetDof(newSection, cell, 0));
3804852b71a7SToby Isaac     PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3805852b71a7SToby Isaac   } else {
3806852b71a7SToby Isaac     PetscInt     cSize;
3807852b71a7SToby Isaac     PetscScalar *values      = NULL;
3808852b71a7SToby Isaac     PetscBool    same_coords = PETSC_TRUE;
3809852b71a7SToby Isaac 
3810852b71a7SToby Isaac     PetscCall(DMPlexVecGetClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3811852b71a7SToby Isaac     PetscAssert(cSize == cDim * P4EST_CHILDREN, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected closure size");
3812852b71a7SToby Isaac     for (int c = 0; c < P4EST_CHILDREN; c++) {
3813852b71a7SToby Isaac       p4est_qcoord_t quad_coords[3];
3814852b71a7SToby Isaac       p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3815852b71a7SToby Isaac       double         corner_coords[3];
3816852b71a7SToby Isaac       double         vert_coords[3];
3817852b71a7SToby Isaac       PetscInt       corner = PetscVertToP4estVert[c];
3818852b71a7SToby Isaac 
3819ad540459SPierre Jolivet       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) vert_coords[d] = PetscRealPart(values[c * cDim + d]);
3820852b71a7SToby Isaac 
3821852b71a7SToby Isaac       quad_coords[0] = quad->x;
3822852b71a7SToby Isaac       quad_coords[1] = quad->y;
3823852b71a7SToby Isaac #ifdef P4_TO_P8
3824852b71a7SToby Isaac       quad_coords[2] = quad->z;
3825852b71a7SToby Isaac #endif
3826ad540459SPierre Jolivet       for (int d = 0; d < 3; d++) quad_coords[d] += (corner & (1 << d)) ? h : 0;
3827852b71a7SToby Isaac #ifndef P4_TO_P8
3828648bc8c4SBarry Smith       PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3829852b71a7SToby Isaac #else
3830648bc8c4SBarry Smith       PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3831852b71a7SToby Isaac #endif
3832852b71a7SToby Isaac       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
3833852b71a7SToby Isaac         if (fabs(vert_coords[d] - corner_coords[d]) > PETSC_SMALL) {
3834852b71a7SToby Isaac           same_coords = PETSC_FALSE;
3835852b71a7SToby Isaac           break;
3836852b71a7SToby Isaac         }
3837852b71a7SToby Isaac       }
3838852b71a7SToby Isaac     }
3839852b71a7SToby Isaac     if (same_coords) {
3840852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, 0));
3841852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3842852b71a7SToby Isaac     } else {
3843852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, cSize));
3844852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, cSize));
3845852b71a7SToby Isaac     }
3846852b71a7SToby Isaac     PetscCall(DMPlexVecRestoreClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3847852b71a7SToby Isaac   }
3848852b71a7SToby Isaac   PetscFunctionReturn(0);
3849852b71a7SToby Isaac }
3850852b71a7SToby Isaac 
38519371c9d4SSatish Balay static PetscErrorCode PforestLocalizeCell(DM plex, PetscInt cDim, DM_Forest_pforest *pforest, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad, PetscScalar coords[]) {
3852852b71a7SToby Isaac   PetscInt cdof, off;
3853852b71a7SToby Isaac 
3854852b71a7SToby Isaac   PetscFunctionBegin;
3855852b71a7SToby Isaac   PetscCall(PetscSectionGetDof(newSection, cell, &cdof));
3856852b71a7SToby Isaac   if (!cdof) PetscFunctionReturn(0);
3857852b71a7SToby Isaac 
3858852b71a7SToby Isaac   PetscCall(PetscSectionGetOffset(newSection, cell, &off));
3859852b71a7SToby Isaac   for (PetscInt c = 0, pos = off; c < P4EST_CHILDREN; c++) {
3860852b71a7SToby Isaac     p4est_qcoord_t quad_coords[3];
3861852b71a7SToby Isaac     p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3862852b71a7SToby Isaac     double         corner_coords[3];
3863852b71a7SToby Isaac     PetscInt       corner = PetscVertToP4estVert[c];
3864852b71a7SToby Isaac 
3865852b71a7SToby Isaac     quad_coords[0] = quad->x;
3866852b71a7SToby Isaac     quad_coords[1] = quad->y;
3867852b71a7SToby Isaac #ifdef P4_TO_P8
3868852b71a7SToby Isaac     quad_coords[2] = quad->z;
3869852b71a7SToby Isaac #endif
3870ad540459SPierre Jolivet     for (int d = 0; d < 3; d++) quad_coords[d] += (corner & (1 << d)) ? h : 0;
3871852b71a7SToby Isaac #ifndef P4_TO_P8
3872648bc8c4SBarry Smith     PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3873852b71a7SToby Isaac #else
3874648bc8c4SBarry Smith     PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3875852b71a7SToby Isaac #endif
3876ad540459SPierre Jolivet     for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) coords[pos++] = corner_coords[d];
3877ad540459SPierre Jolivet     for (PetscInt d = PetscMin(cDim, 3); d < cDim; d++) coords[pos++] = 0.;
3878852b71a7SToby Isaac   }
3879852b71a7SToby Isaac   PetscFunctionReturn(0);
3880852b71a7SToby Isaac }
3881852b71a7SToby Isaac 
38829371c9d4SSatish Balay static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex) {
38830a96aa3bSJed Brown   DM_Forest         *forest;
38840a96aa3bSJed Brown   DM_Forest_pforest *pforest;
38856858538eSMatthew G. Knepley   DM                 base, cdm, cdmCell;
3886852b71a7SToby Isaac   Vec                cVec, cVecOld;
3887852b71a7SToby Isaac   PetscSection       oldSection, newSection;
38880a96aa3bSJed Brown   PetscScalar       *coords2;
38896858538eSMatthew G. Knepley   const PetscReal   *L;
38900a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd, coarsePoint;
3891852b71a7SToby Isaac   PetscInt           cDim, newStart, newEnd;
3892852b71a7SToby Isaac   PetscInt           v, vStart, vEnd, cp, cStart, cEnd, cEndInterior;
38930a96aa3bSJed Brown   p4est_topidx_t     flt, llt, t;
38940a96aa3bSJed Brown   p4est_tree_t      *trees;
38956858538eSMatthew G. Knepley   PetscBool          baseLocalized = PETSC_FALSE;
38960a96aa3bSJed Brown 
38970a96aa3bSJed Brown   PetscFunctionBegin;
38984fb89dddSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dm, NULL, NULL, &L));
38990a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
39009566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cDim));
39019566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
39026858538eSMatthew G. Knepley   if (base) PetscCall(DMGetCoordinatesLocalized(base, &baseLocalized));
39030a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
39046858538eSMatthew G. Knepley   if (!baseLocalized && !L) PetscFunctionReturn(0);
39059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &newStart, &newEnd));
39060a96aa3bSJed Brown 
39079566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newSection));
39089566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(newSection, 1));
39099566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim));
39109566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSection, newStart, newEnd));
39110a96aa3bSJed Brown 
39129566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &oldSection));
39139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
3914852b71a7SToby Isaac   PetscCall(DMGetCoordinatesLocal(plex, &cVecOld));
39150a96aa3bSJed Brown 
39160a96aa3bSJed Brown   forest      = (DM_Forest *)dm->data;
39170a96aa3bSJed Brown   pforest     = (DM_Forest_pforest *)forest->data;
39180a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
39190a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
39200a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
39210a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
39220a96aa3bSJed Brown   trees       = (p4est_tree_t *)pforest->forest->trees->array;
39230a96aa3bSJed Brown 
39249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
39259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(plex, &cEndInterior, NULL));
39260a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
3927852b71a7SToby Isaac   cp   = 0;
39280a96aa3bSJed Brown   if (cLocalStart > 0) {
39290a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
3930852b71a7SToby Isaac     PetscInt          cell;
39310a96aa3bSJed Brown 
3932852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
3933852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
3934852b71a7SToby Isaac 
39350a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
3936852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
39370a96aa3bSJed Brown     }
39380a96aa3bSJed Brown   }
39390a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
39400a96aa3bSJed Brown     p4est_tree_t     *tree     = &(trees[t]);
39410a96aa3bSJed Brown     PetscInt          offset   = cLocalStart + tree->quadrants_offset;
39420a96aa3bSJed Brown     PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
3943852b71a7SToby Isaac     p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
39440a96aa3bSJed Brown     PetscInt          i;
39450a96aa3bSJed Brown 
39460a96aa3bSJed Brown     if (!numQuads) continue;
39470a96aa3bSJed Brown     coarsePoint = t;
3948852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
3949852b71a7SToby Isaac       PetscInt          cell = i + offset;
3950852b71a7SToby Isaac       p4est_quadrant_t *quad = &quads[i];
39510a96aa3bSJed Brown 
3952852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
39530a96aa3bSJed Brown     }
39540a96aa3bSJed Brown   }
39550a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
39560a96aa3bSJed Brown     p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
39570a96aa3bSJed Brown     PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
39580a96aa3bSJed Brown     PetscInt          count;
39590a96aa3bSJed Brown 
3960852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
39610a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
39620a96aa3bSJed Brown       coarsePoint            = quad->p.which_tree;
3963852b71a7SToby Isaac       PetscInt cell          = count + cLocalEnd;
39640a96aa3bSJed Brown 
3965852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
39660a96aa3bSJed Brown     }
39670a96aa3bSJed Brown   }
3968852b71a7SToby Isaac   PetscAssert(cp == cEnd - cStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT, cp, cEnd - cStart);
39690a96aa3bSJed Brown 
39709566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSection));
39716858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(plex, &cdm));
39726858538eSMatthew G. Knepley   PetscCall(DMClone(cdm, &cdmCell));
39736858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(plex, cdmCell));
39746858538eSMatthew G. Knepley   PetscCall(DMDestroy(&cdmCell));
39756858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateSection(plex, cDim, newSection));
39769566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &v));
39779566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
39789566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)cVec, "coordinates"));
39799566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(cVec, cDim));
39809566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE));
39819566063dSJacob Faibussowitsch   PetscCall(VecSetType(cVec, VECSTANDARD));
39829566063dSJacob Faibussowitsch   PetscCall(VecSet(cVec, PETSC_MIN_REAL));
39830a96aa3bSJed Brown 
39840a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
39856858538eSMatthew G. Knepley   PetscCall(VecGetArray(cVec, &coords2));
3986852b71a7SToby Isaac   cp = 0;
3987852b71a7SToby Isaac   if (cLocalStart > 0) {
3988852b71a7SToby Isaac     p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
3989852b71a7SToby Isaac     PetscInt          cell;
3990852b71a7SToby Isaac 
3991852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
3992852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
3993852b71a7SToby Isaac 
3994852b71a7SToby Isaac       coarsePoint = quad->p.which_tree;
3995852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
3996852b71a7SToby Isaac     }
3997852b71a7SToby Isaac   }
39980a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
39990a96aa3bSJed Brown     p4est_tree_t     *tree     = &(trees[t]);
40000a96aa3bSJed Brown     PetscInt          offset   = cLocalStart + tree->quadrants_offset;
40010a96aa3bSJed Brown     PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
4002852b71a7SToby Isaac     p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
4003852b71a7SToby Isaac     PetscInt          i;
40040a96aa3bSJed Brown 
40050a96aa3bSJed Brown     if (!numQuads) continue;
4006852b71a7SToby Isaac     coarsePoint = t;
4007852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4008852b71a7SToby Isaac       PetscInt          cell = i + offset;
40090a96aa3bSJed Brown       p4est_quadrant_t *quad = &quads[i];
40100a96aa3bSJed Brown 
4011852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4012852b71a7SToby Isaac     }
4013852b71a7SToby Isaac   }
4014852b71a7SToby Isaac   if (cLocalEnd - cLocalStart < cEnd - cStart) {
4015852b71a7SToby Isaac     p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
4016852b71a7SToby Isaac     PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
4017852b71a7SToby Isaac     PetscInt          count;
40180a96aa3bSJed Brown 
4019852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
4020852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
4021852b71a7SToby Isaac       coarsePoint            = quad->p.which_tree;
4022852b71a7SToby Isaac       PetscInt cell          = count + cLocalEnd;
40230a96aa3bSJed Brown 
4024852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
40250a96aa3bSJed Brown     }
40260a96aa3bSJed Brown   }
40279566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cVec, &coords2));
40286858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(plex, cVec));
40299566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cVec));
40309566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&newSection));
40310a96aa3bSJed Brown   PetscFunctionReturn(0);
40320a96aa3bSJed Brown }
40330a96aa3bSJed Brown 
40340a96aa3bSJed Brown #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
40359371c9d4SSatish Balay static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm) {
40360a96aa3bSJed Brown   DM_Forest         *forest;
40370a96aa3bSJed Brown   DM_Forest_pforest *pforest;
40380a96aa3bSJed Brown 
40390a96aa3bSJed Brown   PetscFunctionBegin;
40400a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
40410a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
40429566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointAdaptToSelfSF)));
40439566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointSelfToAdaptSF)));
40449566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
40459566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
40460a96aa3bSJed Brown   PetscFunctionReturn(0);
40470a96aa3bSJed Brown }
40480a96aa3bSJed Brown 
40499371c9d4SSatish Balay static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex) {
40500a96aa3bSJed Brown   DM_Forest           *forest;
40510a96aa3bSJed Brown   DM_Forest_pforest   *pforest;
40520a96aa3bSJed Brown   DM                   refTree, newPlex, base;
40530a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
40540a96aa3bSJed Brown   MPI_Comm             comm;
40550a96aa3bSJed Brown   PetscBool            isPforest;
40560a96aa3bSJed Brown   PetscInt             dim;
40570a96aa3bSJed Brown   PetscInt             overlap;
40580a96aa3bSJed Brown   p4est_connect_type_t ctype;
40590a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
40600a96aa3bSJed Brown   sc_array_t          *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
40610a96aa3bSJed Brown   PetscSection         parentSection;
40620a96aa3bSJed Brown   PetscSF              pointSF;
40630a96aa3bSJed Brown   size_t               zz, count;
40640a96aa3bSJed Brown   PetscInt             pStart, pEnd;
40650a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
40660a96aa3bSJed Brown 
40670a96aa3bSJed Brown   PetscFunctionBegin;
40680a96aa3bSJed Brown 
40690a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
40700a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
40719566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPFOREST, &isPforest));
407228b400f6SJacob Faibussowitsch   PetscCheck(isPforest, comm, PETSC_ERR_ARG_WRONG, "Expected DM type %s, got %s", DMPFOREST, ((PetscObject)dm)->type_name);
40739566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
407463a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Expected DM dimension %d, got %" PetscInt_FMT, P4EST_DIM, dim);
40750a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
40760a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
40779566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
407848a46eb9SPierre Jolivet   if (base) PetscCall(DMGetLabel(base, "ghost", &ghostLabelBase));
40790a96aa3bSJed Brown   if (!pforest->plex) {
40800a96aa3bSJed Brown     PetscMPIInt size;
40810a96aa3bSJed Brown 
40829566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
40839566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm, &newPlex));
40849566063dSJacob Faibussowitsch     PetscCall(DMSetType(newPlex, DMPLEX));
40859566063dSJacob Faibussowitsch     PetscCall(DMSetMatType(newPlex, dm->mattype));
40860a96aa3bSJed Brown     /* share labels */
40879566063dSJacob Faibussowitsch     PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
40889566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
40899566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
40909566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
40910a96aa3bSJed Brown     if (adjDim == 0) {
40920a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
40930a96aa3bSJed Brown     } else if (adjCodim == 1) {
40940a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
40950a96aa3bSJed Brown #if defined(P4_TO_P8)
40960a96aa3bSJed Brown     } else if (adjDim == 1) {
40970a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
40980a96aa3bSJed Brown #endif
40990a96aa3bSJed Brown     } else {
410063a3b9bcSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid adjacency dimension %" PetscInt_FMT, adjDim);
41010a96aa3bSJed Brown     }
410263a3b9bcSJacob Faibussowitsch     PetscCheck(ctype == P4EST_CONNECT_FULL, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Adjacency dimension %" PetscInt_FMT " / codimension %" PetscInt_FMT " not supported yet", adjDim, adjCodim);
41039566063dSJacob Faibussowitsch     PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
410460667520SVaclav Hapla     PetscCall(DMPlexSetOverlap_Plex(newPlex, NULL, overlap));
41050a96aa3bSJed Brown 
41060a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
41070a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
41080a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
41090a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
41100a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
41110a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
41120a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
41130a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
41140a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
41150a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
41160a96aa3bSJed Brown 
4117792fecdfSBarry Smith     PetscCallP4est(p4est_get_plex_data_ext, (pforest->forest, &pforest->ghost, &pforest->lnodes, ctype, (int)((size > 1) ? overlap : 0), &first_local_quad, points_per_dim, cone_sizes, cones, cone_orientations, coords, children, parents, childids, leaves, remotes, 1));
41180a96aa3bSJed Brown 
41190a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt)first_local_quad;
41200a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt)pforest->forest->local_num_quadrants;
41219566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
41229566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
41239566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
41249566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
41259566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, coordDim));
41269566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(children));
41279566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(parents));
41289566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(childids));
41299566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(leaves));
41309566063dSJacob Faibussowitsch     PetscCall(locidx_pair_to_PetscSFNode(remotes));
41310a96aa3bSJed Brown 
41329566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(newPlex, P4EST_DIM));
41339566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDim(newPlex, coordDim));
41349566063dSJacob Faibussowitsch     PetscCall(DMPlexSetMaxProjectionHeight(newPlex, P4EST_DIM - 1));
41359566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(newPlex, P4EST_DIM, (PetscInt *)points_per_dim->array, (PetscInt *)cone_sizes->array, (PetscInt *)cones->array, (PetscInt *)cone_orientations->array, (PetscScalar *)coords->array));
41369566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(newPlex));
41379566063dSJacob Faibussowitsch     PetscCall(DMCreateReferenceTree_pforest(comm, &refTree));
41389566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(newPlex, refTree));
41399566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(comm, &parentSection));
41409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(newPlex, &pStart, &pEnd));
41419566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
41420a96aa3bSJed Brown     count = children->elem_count;
41430a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
41440a96aa3bSJed Brown       PetscInt child = *((PetscInt *)sc_array_index(children, zz));
41450a96aa3bSJed Brown 
41469566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(parentSection, child, 1));
41470a96aa3bSJed Brown     }
41489566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
41499566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(newPlex, parentSection, (PetscInt *)parents->array, (PetscInt *)childids->array));
41509566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&parentSection));
41519566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &pointSF));
41520a96aa3bSJed Brown     /*
41530a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
41540a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
41550a96aa3bSJed Brown     */
41569566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(pointSF, pEnd - pStart, (PetscInt)leaves->elem_count, (PetscInt *)leaves->array, PETSC_COPY_VALUES, (PetscSFNode *)remotes->array, PETSC_COPY_VALUES));
41579566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(newPlex, pointSF));
41589566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(dm, pointSF));
41590a96aa3bSJed Brown     {
41600a96aa3bSJed Brown       DM coordDM;
41610a96aa3bSJed Brown 
41629566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex, &coordDM));
41639566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(coordDM, pointSF));
41640a96aa3bSJed Brown     }
41659566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointSF));
41660a96aa3bSJed Brown     sc_array_destroy(points_per_dim);
41670a96aa3bSJed Brown     sc_array_destroy(cone_sizes);
41680a96aa3bSJed Brown     sc_array_destroy(cones);
41690a96aa3bSJed Brown     sc_array_destroy(cone_orientations);
41700a96aa3bSJed Brown     sc_array_destroy(coords);
41710a96aa3bSJed Brown     sc_array_destroy(children);
41720a96aa3bSJed Brown     sc_array_destroy(parents);
41730a96aa3bSJed Brown     sc_array_destroy(childids);
41740a96aa3bSJed Brown     sc_array_destroy(leaves);
41750a96aa3bSJed Brown     sc_array_destroy(remotes);
41760a96aa3bSJed Brown 
41770a96aa3bSJed Brown     {
41784fb89dddSMatthew G. Knepley       const PetscReal *maxCell, *Lstart, *L;
41790a96aa3bSJed Brown 
41804fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
41814fb89dddSMatthew G. Knepley       PetscCall(DMSetPeriodicity(newPlex, maxCell, Lstart, L));
41829566063dSJacob Faibussowitsch       PetscCall(DMPforestLocalizeCoordinates(dm, newPlex));
41830a96aa3bSJed Brown     }
41840a96aa3bSJed Brown 
41850a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
41860a96aa3bSJed Brown       Vec                coordsGlobal, coordsLocal;
41870a96aa3bSJed Brown       const PetscScalar *globalArray;
41880a96aa3bSJed Brown       PetscScalar       *localArray;
41890a96aa3bSJed Brown       PetscSF            coordSF;
41900a96aa3bSJed Brown       DM                 coordDM;
41910a96aa3bSJed Brown 
41929566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex, &coordDM));
41939566063dSJacob Faibussowitsch       PetscCall(DMGetSectionSF(coordDM, &coordSF));
41949566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinates(newPlex, &coordsGlobal));
41959566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal));
41969566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordsGlobal, &globalArray));
41979566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordsLocal, &localArray));
41989566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coordSF, MPIU_SCALAR, globalArray, localArray, MPI_REPLACE));
41999566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coordSF, MPIU_SCALAR, globalArray, localArray, MPI_REPLACE));
42009566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordsLocal, &localArray));
42019566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray));
42029566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal));
42030a96aa3bSJed Brown     }
42049566063dSJacob Faibussowitsch     PetscCall(DMPforestMapCoordinates(dm, newPlex));
42050a96aa3bSJed Brown 
42060a96aa3bSJed Brown     pforest->plex = newPlex;
42070a96aa3bSJed Brown 
42080a96aa3bSJed Brown     /* copy labels */
42099566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsFinalize(dm, newPlex));
42100a96aa3bSJed Brown 
42110a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
42120a96aa3bSJed Brown       PetscInt numAdded;
42130a96aa3bSJed Brown       DM       newPlexGhosted;
42140a96aa3bSJed Brown       void    *ctx;
42150a96aa3bSJed Brown 
42169566063dSJacob Faibussowitsch       PetscCall(DMPlexConstructGhostCells(newPlex, pforest->ghostName, &numAdded, &newPlexGhosted));
42179566063dSJacob Faibussowitsch       PetscCall(DMGetApplicationContext(newPlex, &ctx));
42189566063dSJacob Faibussowitsch       PetscCall(DMSetApplicationContext(newPlexGhosted, ctx));
42190a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
42209566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(newPlexGhosted, &pointSF));
42219566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(dm, pointSF));
42229566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&newPlex));
42239566063dSJacob Faibussowitsch       PetscCall(DMPlexSetReferenceTree(newPlexGhosted, refTree));
42249566063dSJacob Faibussowitsch       PetscCall(DMForestClearAdaptivityForest_pforest(dm));
42250a96aa3bSJed Brown       newPlex = newPlexGhosted;
42260a96aa3bSJed Brown 
42270a96aa3bSJed Brown       /* share the labels back */
42289566063dSJacob Faibussowitsch       PetscCall(DMDestroyLabelLinkList_Internal(dm));
42299566063dSJacob Faibussowitsch       PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
42300a96aa3bSJed Brown       pforest->plex = newPlex;
42310a96aa3bSJed Brown     }
42329566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&refTree));
42330a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
4234d0609cedSBarry Smith       PetscObjectOptionsBegin((PetscObject)newPlex);
4235dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(newPlex, PetscOptionsObject));
4236dbbe0bcdSBarry Smith       PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)newPlex, PetscOptionsObject));
4237d0609cedSBarry Smith       PetscOptionsEnd();
42380a96aa3bSJed Brown     }
42399566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(newPlex, NULL, "-dm_p4est_plex_view"));
42400a96aa3bSJed Brown     {
42416858538eSMatthew G. Knepley       DM           cdm;
42420a96aa3bSJed Brown       PetscSection coordsSec;
42430a96aa3bSJed Brown       Vec          coords;
42440a96aa3bSJed Brown       PetscInt     cDim;
42450a96aa3bSJed Brown 
42469566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(newPlex, &cDim));
42479566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(newPlex, &coordsSec));
42489566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinateSection(dm, cDim, coordsSec));
42499566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coords));
42509566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(dm, coords));
42516858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateDM(newPlex, &cdm));
42526858538eSMatthew G. Knepley       if (cdm) PetscCall(DMSetCellCoordinateDM(dm, cdm));
42536858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateSection(newPlex, &coordsSec));
42546858538eSMatthew G. Knepley       if (coordsSec) PetscCall(DMSetCellCoordinateSection(dm, cDim, coordsSec));
42556858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinatesLocal(newPlex, &coords));
42566858538eSMatthew G. Knepley       if (coords) PetscCall(DMSetCellCoordinatesLocal(dm, coords));
42570a96aa3bSJed Brown     }
42580a96aa3bSJed Brown   }
42590a96aa3bSJed Brown   newPlex = pforest->plex;
42600a96aa3bSJed Brown   if (plex) {
42619566063dSJacob Faibussowitsch     PetscCall(DMClone(newPlex, plex));
42626858538eSMatthew G. Knepley #if 0
42639566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
42649566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDM(*plex,coordDM));
42656858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(newPlex,&coordDM));
42666858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*plex,coordDM));
42676858538eSMatthew G. Knepley #endif
42689566063dSJacob Faibussowitsch     PetscCall(DMShareDiscretization(dm, *plex));
42690a96aa3bSJed Brown   }
42700a96aa3bSJed Brown   PetscFunctionReturn(0);
42710a96aa3bSJed Brown }
42720a96aa3bSJed Brown 
42739371c9d4SSatish Balay static PetscErrorCode DMSetFromOptions_pforest(DM dm, PetscOptionItems *PetscOptionsObject) {
42740a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
42750a96aa3bSJed Brown   char               stringBuffer[256];
42760a96aa3bSJed Brown   PetscBool          flg;
42770a96aa3bSJed Brown 
42780a96aa3bSJed Brown   PetscFunctionBegin;
4279dbbe0bcdSBarry Smith   PetscCall(DMSetFromOptions_Forest(dm, PetscOptionsObject));
4280d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DM" P4EST_STRING " options");
42819566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening", "partition forest to allow for coarsening", "DMP4estSetPartitionForCoarsening", pforest->partition_for_coarsening, &(pforest->partition_for_coarsening), NULL));
42829566063dSJacob Faibussowitsch   PetscCall(PetscOptionsString("-dm_p4est_ghost_label_name", "the name of the ghost label when converting from a DMPlex", NULL, NULL, stringBuffer, sizeof(stringBuffer), &flg));
4283d0609cedSBarry Smith   PetscOptionsHeadEnd();
42840a96aa3bSJed Brown   if (flg) {
42859566063dSJacob Faibussowitsch     PetscCall(PetscFree(pforest->ghostName));
42869566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(stringBuffer, &pforest->ghostName));
42870a96aa3bSJed Brown   }
42880a96aa3bSJed Brown   PetscFunctionReturn(0);
42890a96aa3bSJed Brown }
42900a96aa3bSJed Brown 
42910a96aa3bSJed Brown #if !defined(P4_TO_P8)
42920a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
42930a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
42940a96aa3bSJed Brown #else
42950a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
42960a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
42970a96aa3bSJed Brown #endif
42980a96aa3bSJed Brown 
42999371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg) {
43000a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43010a96aa3bSJed Brown 
43020a96aa3bSJed Brown   PetscFunctionBegin;
43030a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43040a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43050a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
43060a96aa3bSJed Brown   PetscFunctionReturn(0);
43070a96aa3bSJed Brown }
43080a96aa3bSJed Brown 
43099371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg) {
43100a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43110a96aa3bSJed Brown 
43120a96aa3bSJed Brown   PetscFunctionBegin;
43130a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43140a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43150a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
43160a96aa3bSJed Brown   PetscFunctionReturn(0);
43170a96aa3bSJed Brown }
43180a96aa3bSJed Brown 
43199371c9d4SSatish Balay static PetscErrorCode DMPforestGetPlex(DM dm, DM *plex) {
43200a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43210a96aa3bSJed Brown 
43220a96aa3bSJed Brown   PetscFunctionBegin;
43230a96aa3bSJed Brown   if (plex) *plex = NULL;
43249566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
43250a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
432648a46eb9SPierre Jolivet   if (!pforest->plex) PetscCall(DMConvert_pforest_plex(dm, DMPLEX, NULL));
43279566063dSJacob Faibussowitsch   PetscCall(DMShareDiscretization(dm, pforest->plex));
43280a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
43290a96aa3bSJed Brown   PetscFunctionReturn(0);
43300a96aa3bSJed Brown }
43310a96aa3bSJed Brown 
43320a96aa3bSJed Brown #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
43339371c9d4SSatish Balay static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) {
43340a96aa3bSJed Brown   PetscSection gsc, gsf;
43350a96aa3bSJed Brown   PetscInt     m, n;
43360a96aa3bSJed Brown   DM           cdm;
43370a96aa3bSJed Brown 
43380a96aa3bSJed Brown   PetscFunctionBegin;
43399566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
43409566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
43419566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
43429566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
43430a96aa3bSJed Brown 
43449566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmFine), interpolation));
43459566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
43469566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, MATAIJ));
43470a96aa3bSJed Brown 
43489566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
434908401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse, PetscObjectComm((PetscObject)dmFine), PETSC_ERR_SUP, "Only interpolation from coarse DM for now");
43500a96aa3bSJed Brown 
43510a96aa3bSJed Brown   {
43520a96aa3bSJed Brown     DM        plexF, plexC;
43530a96aa3bSJed Brown     PetscSF   sf;
43540a96aa3bSJed Brown     PetscInt *cids;
43550a96aa3bSJed Brown     PetscInt  dofPerDim[4] = {1, 1, 1, 1};
43560a96aa3bSJed Brown 
43579566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse, &plexC));
43589566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine, &plexF));
43599566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
43609566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
43619566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
43629566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
43639566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
43640a96aa3bSJed Brown   }
43659566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
43660a96aa3bSJed Brown   /* Use naive scaling */
43679566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
43680a96aa3bSJed Brown   PetscFunctionReturn(0);
43690a96aa3bSJed Brown }
43700a96aa3bSJed Brown 
43710a96aa3bSJed Brown #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
43729371c9d4SSatish Balay static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection) {
43730a96aa3bSJed Brown   PetscSection gsc, gsf;
43740a96aa3bSJed Brown   PetscInt     m, n;
43750a96aa3bSJed Brown   DM           cdm;
43760a96aa3bSJed Brown 
43770a96aa3bSJed Brown   PetscFunctionBegin;
43789566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
43799566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n));
43809566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
43819566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m));
43820a96aa3bSJed Brown 
43839566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmFine), injection));
43849566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
43859566063dSJacob Faibussowitsch   PetscCall(MatSetType(*injection, MATAIJ));
43860a96aa3bSJed Brown 
43879566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
438808401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse, PetscObjectComm((PetscObject)dmFine), PETSC_ERR_SUP, "Only injection to coarse DM for now");
43890a96aa3bSJed Brown 
43900a96aa3bSJed Brown   {
43910a96aa3bSJed Brown     DM        plexF, plexC;
43920a96aa3bSJed Brown     PetscSF   sf;
43930a96aa3bSJed Brown     PetscInt *cids;
43940a96aa3bSJed Brown     PetscInt  dofPerDim[4] = {1, 1, 1, 1};
43950a96aa3bSJed Brown 
43969566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse, &plexC));
43979566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine, &plexF));
43989566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
43999566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
44009566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
44019566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
44029566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
44030a96aa3bSJed Brown   }
44049566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
44050a96aa3bSJed Brown   /* Use naive scaling */
44060a96aa3bSJed Brown   PetscFunctionReturn(0);
44070a96aa3bSJed Brown }
44080a96aa3bSJed Brown 
44090a96aa3bSJed Brown #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
44109371c9d4SSatish Balay static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut) {
44110a96aa3bSJed Brown   DM        dmIn, dmVecIn, base, basec, plex, coarseDM;
44120a96aa3bSJed Brown   DM       *hierarchy;
44130a96aa3bSJed Brown   PetscSF   sfRed = NULL;
44140a96aa3bSJed Brown   PetscDS   ds;
44150a96aa3bSJed Brown   Vec       vecInLocal, vecOutLocal;
44160a96aa3bSJed Brown   DMLabel   subpointMap;
44170a96aa3bSJed Brown   PetscInt  minLevel, mh, n_hi, i;
44180a96aa3bSJed Brown   PetscBool hiforest, *hierarchy_forest;
44190a96aa3bSJed Brown 
44200a96aa3bSJed Brown   PetscFunctionBegin;
44219566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vecIn, &dmVecIn));
44229566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmVecIn, &ds));
442328b400f6SJacob Faibussowitsch   PetscCheck(ds, PetscObjectComm((PetscObject)dmVecIn), PETSC_ERR_SUP, "Cannot transfer without a PetscDS object");
44240a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
44250a96aa3bSJed Brown     PetscSection section;
44260a96aa3bSJed Brown     PetscInt     Nf;
44270a96aa3bSJed Brown 
44289566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn, &section));
44299566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
443063a3b9bcSJacob Faibussowitsch     PetscCheck(Nf <= 3, PetscObjectComm((PetscObject)dmVecIn), PETSC_ERR_SUP, "Number of fields %" PetscInt_FMT " are currently not supported! Send an email at petsc-dev@mcs.anl.gov", Nf);
44310a96aa3bSJed Brown   }
44329566063dSJacob Faibussowitsch   PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
443363a3b9bcSJacob Faibussowitsch   PetscCheck(!minLevel, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)", minLevel);
44349566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
443528b400f6SJacob Faibussowitsch   PetscCheck(base, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing base DM");
44360a96aa3bSJed Brown 
44379566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
44380a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
44399566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
44400a96aa3bSJed Brown   } else {
44410a96aa3bSJed Brown     PetscSection secIn, secInRed;
44420a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
44430a96aa3bSJed Brown 
44449566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)base, "_base_migration_sf", (PetscObject *)&sfRed));
444528b400f6SJacob Faibussowitsch     PetscCheck(sfRed, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not the DM set with DMForestSetBaseDM()");
44469566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn), &secInRed));
44479566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF, &vecInRed));
44489566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn, &secIn));
44499566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmVecIn, &vecInLocal));
44509566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmVecIn, vecIn, INSERT_VALUES, vecInLocal));
44519566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmVecIn, vecIn, INSERT_VALUES, vecInLocal));
44529566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeField(dmVecIn, sfRed, secIn, vecInLocal, secInRed, vecInRed));
44539566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmVecIn, &vecInLocal));
44549566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secInRed));
44550a96aa3bSJed Brown     vecIn = vecInRed;
44560a96aa3bSJed Brown   }
44570a96aa3bSJed Brown 
44580a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
44590a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
44600a96aa3bSJed Brown   hiforest = PETSC_TRUE;
44610a96aa3bSJed Brown 
44620a96aa3bSJed Brown   /* upsweep to the coarsest DM */
44630a96aa3bSJed Brown   n_hi     = 0;
44640a96aa3bSJed Brown   coarseDM = dm;
44650a96aa3bSJed Brown   do {
44660a96aa3bSJed Brown     PetscBool isforest;
44670a96aa3bSJed Brown 
44680a96aa3bSJed Brown     dmIn = coarseDM;
44690a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
44709566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dmIn));
44719566063dSJacob Faibussowitsch     PetscCall(DMIsForest(dmIn, &isforest));
447228b400f6SJacob Faibussowitsch     PetscCheck(isforest, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "Cannot currently transfer through a mixed hierarchy! Found DM type %s", ((PetscObject)dmIn)->type_name);
44730a96aa3bSJed Brown     coarseDM = NULL;
447448a46eb9SPierre Jolivet     if (hiforest) PetscCall(DMForestGetAdaptivityForest(dmIn, &coarseDM));
44750a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
44760a96aa3bSJed Brown       hiforest = PETSC_FALSE;
44779566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn, &coarseDM));
44780a96aa3bSJed Brown     }
44790a96aa3bSJed Brown     n_hi++;
44800a96aa3bSJed Brown   } while (coarseDM);
44810a96aa3bSJed Brown 
44829566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n_hi, &hierarchy, n_hi, &hierarchy_forest));
44830a96aa3bSJed Brown 
44840a96aa3bSJed Brown   i        = 0;
44850a96aa3bSJed Brown   hiforest = PETSC_TRUE;
44860a96aa3bSJed Brown   coarseDM = dm;
44870a96aa3bSJed Brown   do {
44880a96aa3bSJed Brown     dmIn     = coarseDM;
44890a96aa3bSJed Brown     coarseDM = NULL;
449048a46eb9SPierre Jolivet     if (hiforest) PetscCall(DMForestGetAdaptivityForest(dmIn, &coarseDM));
44910a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
44920a96aa3bSJed Brown       hiforest = PETSC_FALSE;
44939566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn, &coarseDM));
44940a96aa3bSJed Brown     }
44950a96aa3bSJed Brown     i++;
44960a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
44970a96aa3bSJed Brown   } while (coarseDM);
44980a96aa3bSJed Brown 
44990a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
45009566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn, &plex));
45010a96aa3bSJed Brown 
45020a96aa3bSJed Brown   /* Check this plex is compatible with the base */
45030a96aa3bSJed Brown   {
45040a96aa3bSJed Brown     IS       gnum[2];
45050a96aa3bSJed Brown     PetscInt ncells[2], gncells[2];
45060a96aa3bSJed Brown 
45079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(base, &gnum[0]));
45089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(plex, &gnum[1]));
45099566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[0], NULL, &ncells[0]));
45109566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[1], NULL, &ncells[1]));
45111c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(ncells, gncells, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
451263a3b9bcSJacob Faibussowitsch     PetscCheck(gncells[0] == gncells[1], PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Invalid number of base cells! Expected %" PetscInt_FMT ", found %" PetscInt_FMT, gncells[0] + 1, gncells[1] + 1);
45130a96aa3bSJed Brown   }
45140a96aa3bSJed Brown 
45159566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dmIn, "_forest_base_subpoint_map", &subpointMap));
451628b400f6SJacob Faibussowitsch   PetscCheck(subpointMap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing _forest_base_subpoint_map label");
45170a96aa3bSJed Brown 
45189566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(base, &mh));
45199566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(plex, mh));
45200a96aa3bSJed Brown 
45219566063dSJacob Faibussowitsch   PetscCall(DMClone(base, &basec));
45229566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmVecIn, basec));
45230a96aa3bSJed Brown   if (sfRed) {
45249566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45250a96aa3bSJed Brown     vecInLocal = vecIn;
45260a96aa3bSJed Brown   } else {
45279566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(basec, &vecInLocal));
45289566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(basec, vecIn, INSERT_VALUES, vecInLocal));
45299566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(basec, vecIn, INSERT_VALUES, vecInLocal));
45300a96aa3bSJed Brown   }
45310a96aa3bSJed Brown 
45329566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmIn, &vecOutLocal));
45330a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
45340a96aa3bSJed Brown     PetscSF            basetocoarse;
45350a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
45360a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
45370a96aa3bSJed Brown     PetscMPIInt        rank;
45380a96aa3bSJed Brown     PetscSFNode       *remotes;
45390a96aa3bSJed Brown     PetscSection       secIn, secOut;
45400a96aa3bSJed Brown     PetscInt          *remoteOffsets;
45410a96aa3bSJed Brown     PetscSF            transferSF;
45420a96aa3bSJed Brown     const PetscScalar *inArray;
45430a96aa3bSJed Brown     PetscScalar       *outArray;
45440a96aa3bSJed Brown 
45459566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
45469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(basec, &bStart, &bEnd));
45470a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
45489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &iStart, &iEnd));
45490a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
45500a96aa3bSJed Brown 
45519566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &remotes));
45520a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
45530a96aa3bSJed Brown       PetscInt index;
45540a96aa3bSJed Brown 
45550a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
45569566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(subpointMap, leaf, &index));
45570a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
45580a96aa3bSJed Brown     }
45590a96aa3bSJed Brown 
45609566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
45619566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
45629566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(basetocoarse));
45639566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(basec, &secIn));
45649566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn), &secOut));
45659566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
45669566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
45679566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
45689566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(vecOutLocal, &outArray));
45699566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecInLocal, &inArray));
45709566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray, MPI_REPLACE));
45719566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray, MPI_REPLACE));
45729566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecInLocal, &inArray));
45739566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray));
45749566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferSF));
45759566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secOut));
45769566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&basetocoarse));
45770a96aa3bSJed Brown   }
45789566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecInLocal));
45799566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&basec));
45809566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecIn));
45810a96aa3bSJed Brown 
45820a96aa3bSJed Brown   /* output */
45830a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
45840a96aa3bSJed Brown     Vec vecOut1, vecOut2;
45850a96aa3bSJed Brown     DM  fineDM;
45860a96aa3bSJed Brown 
45879566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmIn, &vecOut1));
45889566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn, vecOutLocal, INSERT_VALUES, vecOut1));
45899566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecOutLocal));
45900a96aa3bSJed Brown     for (i = 1; i < n_hi - 1; i++) {
45910a96aa3bSJed Brown       fineDM = hierarchy[i];
45929566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(fineDM, &vecOut2));
45939566063dSJacob Faibussowitsch       PetscCall(DMForestTransferVec(dmIn, vecOut1, fineDM, vecOut2, PETSC_TRUE, 0.0));
45949566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmIn, &vecOut1));
45950a96aa3bSJed Brown       vecOut1 = vecOut2;
45960a96aa3bSJed Brown       dmIn    = fineDM;
45970a96aa3bSJed Brown     }
45989566063dSJacob Faibussowitsch     PetscCall(DMForestTransferVec(dmIn, vecOut1, dm, vecOut, PETSC_TRUE, 0.0));
45999566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmIn, &vecOut1));
46000a96aa3bSJed Brown   } else {
46019566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn, vecOutLocal, INSERT_VALUES, vecOut));
46029566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecOutLocal));
46030a96aa3bSJed Brown   }
46049566063dSJacob Faibussowitsch   PetscCall(PetscFree2(hierarchy, hierarchy_forest));
46050a96aa3bSJed Brown   PetscFunctionReturn(0);
46060a96aa3bSJed Brown }
46070a96aa3bSJed Brown 
46080a96aa3bSJed Brown #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
46099371c9d4SSatish Balay static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time) {
46100a96aa3bSJed Brown   DM          adaptIn, adaptOut, plexIn, plexOut;
46110a96aa3bSJed Brown   DM_Forest  *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
46120a96aa3bSJed Brown   PetscInt    dofPerDim[] = {1, 1, 1, 1};
46130a96aa3bSJed Brown   PetscSF     inSF = NULL, outSF = NULL;
46140a96aa3bSJed Brown   PetscInt   *inCids = NULL, *outCids = NULL;
46150a96aa3bSJed Brown   DMAdaptFlag purposeIn, purposeOut;
46160a96aa3bSJed Brown 
46170a96aa3bSJed Brown   PetscFunctionBegin;
46180a96aa3bSJed Brown   forestOut = (DM_Forest *)dmOut->data;
46190a96aa3bSJed Brown   forestIn  = (DM_Forest *)dmIn->data;
46200a96aa3bSJed Brown 
46219566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmOut, &adaptOut));
46229566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmOut, &purposeOut));
46230a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *)adaptOut->data : NULL;
46240a96aa3bSJed Brown 
46259566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmIn, &adaptIn));
46269566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmIn, &purposeIn));
46270a96aa3bSJed Brown   forestAdaptIn = adaptIn ? (DM_Forest *)adaptIn->data : NULL;
46280a96aa3bSJed Brown 
46290a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
46300a96aa3bSJed Brown     switch (purposeOut) {
46310a96aa3bSJed Brown     case DM_ADAPT_REFINE:
46329566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
46339566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
46340a96aa3bSJed Brown       break;
46350a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
46360a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
46379566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_TRUE, &outCids));
46389566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
46390a96aa3bSJed Brown       break;
46400a96aa3bSJed Brown     default:
46419566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
46429566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_FALSE, &outCids));
46439566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
46449566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
46450a96aa3bSJed Brown     }
46460a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
46470a96aa3bSJed Brown     switch (purposeIn) {
46480a96aa3bSJed Brown     case DM_ADAPT_REFINE:
46499566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_TRUE, &inCids));
46509566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
46510a96aa3bSJed Brown       break;
46520a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
46530a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
46549566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
46559566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
46560a96aa3bSJed Brown       break;
46570a96aa3bSJed Brown     default:
46589566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
46599566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_FALSE, &outCids));
46609566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
46619566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
46620a96aa3bSJed Brown     }
46630a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "Only support transfer from pre-adaptivity to post-adaptivity right now");
46649566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn, &plexIn));
46659566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmOut, &plexOut));
46660a96aa3bSJed Brown 
46679566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferVecTree(plexIn, vecIn, plexOut, vecOut, inSF, outSF, inCids, outCids, useBCs, time));
46689566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
46699566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
46709566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&inSF));
46719566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&outSF));
46729566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
46739566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
46740a96aa3bSJed Brown   PetscFunctionReturn(0);
46750a96aa3bSJed Brown }
46760a96aa3bSJed Brown 
46770a96aa3bSJed Brown #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
46789371c9d4SSatish Balay static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm, DM *cdm) {
46790a96aa3bSJed Brown   DM plex;
46800a96aa3bSJed Brown 
46810a96aa3bSJed Brown   PetscFunctionBegin;
46820a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
46839566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
46849566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(plex, cdm));
46859566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)*cdm));
46860a96aa3bSJed Brown   PetscFunctionReturn(0);
46870a96aa3bSJed Brown }
46880a96aa3bSJed Brown 
46890a96aa3bSJed Brown #define VecViewLocal_pforest _append_pforest(VecViewLocal)
46909371c9d4SSatish Balay static PetscErrorCode VecViewLocal_pforest(Vec vec, PetscViewer viewer) {
46910a96aa3bSJed Brown   DM dm, plex;
46920a96aa3bSJed Brown 
46930a96aa3bSJed Brown   PetscFunctionBegin;
46949566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
46959566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
46969566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
46979566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Local(vec, viewer));
46989566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
46990a96aa3bSJed Brown   PetscFunctionReturn(0);
47000a96aa3bSJed Brown }
47010a96aa3bSJed Brown 
47020a96aa3bSJed Brown #define VecView_pforest _append_pforest(VecView)
47039371c9d4SSatish Balay static PetscErrorCode VecView_pforest(Vec vec, PetscViewer viewer) {
47040a96aa3bSJed Brown   DM dm, plex;
47050a96aa3bSJed Brown 
47060a96aa3bSJed Brown   PetscFunctionBegin;
47079566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47089566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47099566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47109566063dSJacob Faibussowitsch   PetscCall(VecView_Plex(vec, viewer));
47119566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
47120a96aa3bSJed Brown   PetscFunctionReturn(0);
47130a96aa3bSJed Brown }
47140a96aa3bSJed Brown 
47150a96aa3bSJed Brown #define VecView_pforest_Native _infix_pforest(VecView, _Native)
47169371c9d4SSatish Balay static PetscErrorCode VecView_pforest_Native(Vec vec, PetscViewer viewer) {
47170a96aa3bSJed Brown   DM dm, plex;
47180a96aa3bSJed Brown 
47190a96aa3bSJed Brown   PetscFunctionBegin;
47209566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47219566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47229566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47239566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Native(vec, viewer));
47249566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
47250a96aa3bSJed Brown   PetscFunctionReturn(0);
47260a96aa3bSJed Brown }
47270a96aa3bSJed Brown 
47280a96aa3bSJed Brown #define VecLoad_pforest _append_pforest(VecLoad)
47299371c9d4SSatish Balay static PetscErrorCode VecLoad_pforest(Vec vec, PetscViewer viewer) {
47300a96aa3bSJed Brown   DM dm, plex;
47310a96aa3bSJed Brown 
47320a96aa3bSJed Brown   PetscFunctionBegin;
47339566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47349566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47359566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47369566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex(vec, viewer));
47379566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
47380a96aa3bSJed Brown   PetscFunctionReturn(0);
47390a96aa3bSJed Brown }
47400a96aa3bSJed Brown 
47410a96aa3bSJed Brown #define VecLoad_pforest_Native _infix_pforest(VecLoad, _Native)
47429371c9d4SSatish Balay static PetscErrorCode VecLoad_pforest_Native(Vec vec, PetscViewer viewer) {
47430a96aa3bSJed Brown   DM dm, plex;
47440a96aa3bSJed Brown 
47450a96aa3bSJed Brown   PetscFunctionBegin;
47469566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47479566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47489566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47499566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex_Native(vec, viewer));
47509566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
47510a96aa3bSJed Brown   PetscFunctionReturn(0);
47520a96aa3bSJed Brown }
47530a96aa3bSJed Brown 
47540a96aa3bSJed Brown #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
47559371c9d4SSatish Balay static PetscErrorCode DMCreateGlobalVector_pforest(DM dm, Vec *vec) {
47560a96aa3bSJed Brown   PetscFunctionBegin;
47579566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
47589566063dSJacob Faibussowitsch   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
47599566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
47609566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
47619566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
47629566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
47630a96aa3bSJed Brown   PetscFunctionReturn(0);
47640a96aa3bSJed Brown }
47650a96aa3bSJed Brown 
47660a96aa3bSJed Brown #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
47679371c9d4SSatish Balay static PetscErrorCode DMCreateLocalVector_pforest(DM dm, Vec *vec) {
47680a96aa3bSJed Brown   PetscFunctionBegin;
47699566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
47709566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
47710a96aa3bSJed Brown   PetscFunctionReturn(0);
47720a96aa3bSJed Brown }
47730a96aa3bSJed Brown 
47740a96aa3bSJed Brown #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
47759371c9d4SSatish Balay static PetscErrorCode DMCreateMatrix_pforest(DM dm, Mat *mat) {
47760a96aa3bSJed Brown   DM plex;
47770a96aa3bSJed Brown 
47780a96aa3bSJed Brown   PetscFunctionBegin;
47790a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47809566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47810a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only; /* maybe this should go into forest->plex */
47829566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(plex, mat));
47839566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*mat, dm));
47840a96aa3bSJed Brown   PetscFunctionReturn(0);
47850a96aa3bSJed Brown }
47860a96aa3bSJed Brown 
47870a96aa3bSJed Brown #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
47889371c9d4SSatish Balay static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) {
47890a96aa3bSJed Brown   DM plex;
47900a96aa3bSJed Brown 
47910a96aa3bSJed Brown   PetscFunctionBegin;
47920a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47939566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47949566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(plex, time, funcs, ctxs, mode, localX));
47950a96aa3bSJed Brown   PetscFunctionReturn(0);
47960a96aa3bSJed Brown }
47970a96aa3bSJed Brown 
47980a96aa3bSJed Brown #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
47999371c9d4SSatish Balay static PetscErrorCode DMProjectFunctionLabelLocal_pforest(DM dm, PetscReal time, DMLabel label, PetscInt numIds, const PetscInt ids[], PetscInt Ncc, const PetscInt comps[], PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX) {
48000a96aa3bSJed Brown   DM plex;
48010a96aa3bSJed Brown 
48020a96aa3bSJed Brown   PetscFunctionBegin;
48030a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48049566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48059566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(plex, time, label, numIds, ids, Ncc, comps, funcs, ctxs, mode, localX));
48060a96aa3bSJed Brown   PetscFunctionReturn(0);
48070a96aa3bSJed Brown }
48080a96aa3bSJed Brown 
48090a96aa3bSJed Brown #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
48109371c9d4SSatish Balay PetscErrorCode DMProjectFieldLocal_pforest(DM dm, PetscReal time, Vec localU, void (**funcs)(PetscInt, PetscInt, PetscInt, const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]), InsertMode mode, Vec localX) {
48110a96aa3bSJed Brown   DM plex;
48120a96aa3bSJed Brown 
48130a96aa3bSJed Brown   PetscFunctionBegin;
48140a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48159566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48169566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(plex, time, localU, funcs, mode, localX));
48170a96aa3bSJed Brown   PetscFunctionReturn(0);
48180a96aa3bSJed Brown }
48190a96aa3bSJed Brown 
48200a96aa3bSJed Brown #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
48219371c9d4SSatish Balay PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff) {
48220a96aa3bSJed Brown   DM plex;
48230a96aa3bSJed Brown 
48240a96aa3bSJed Brown   PetscFunctionBegin;
48250a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48269566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48279566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(plex, time, funcs, ctxs, X, diff));
48280a96aa3bSJed Brown   PetscFunctionReturn(0);
48290a96aa3bSJed Brown }
48300a96aa3bSJed Brown 
48310a96aa3bSJed Brown #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
48329371c9d4SSatish Balay PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[]) {
48330a96aa3bSJed Brown   DM plex;
48340a96aa3bSJed Brown 
48350a96aa3bSJed Brown   PetscFunctionBegin;
48360a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48379566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48389566063dSJacob Faibussowitsch   PetscCall(DMComputeL2FieldDiff(plex, time, funcs, ctxs, X, diff));
48390a96aa3bSJed Brown   PetscFunctionReturn(0);
48400a96aa3bSJed Brown }
48410a96aa3bSJed Brown 
48420a96aa3bSJed Brown #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
48439371c9d4SSatish Balay static PetscErrorCode DMCreatelocalsection_pforest(DM dm) {
48440a96aa3bSJed Brown   DM           plex;
48450a96aa3bSJed Brown   PetscSection section;
48460a96aa3bSJed Brown 
48470a96aa3bSJed Brown   PetscFunctionBegin;
48480a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48499566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48509566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(plex, &section));
48519566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dm, section));
48520a96aa3bSJed Brown   PetscFunctionReturn(0);
48530a96aa3bSJed Brown }
48540a96aa3bSJed Brown 
48550a96aa3bSJed Brown #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
48569371c9d4SSatish Balay static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm) {
48570a96aa3bSJed Brown   DM           plex;
48580a96aa3bSJed Brown   Mat          mat;
485979769bd5SJed Brown   Vec          bias;
48600a96aa3bSJed Brown   PetscSection section;
48610a96aa3bSJed Brown 
48620a96aa3bSJed Brown   PetscFunctionBegin;
48630a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48649566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48659566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(plex, &section, &mat, &bias));
48669566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, section, mat, bias));
48670a96aa3bSJed Brown   PetscFunctionReturn(0);
48680a96aa3bSJed Brown }
48690a96aa3bSJed Brown 
48700a96aa3bSJed Brown #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
48719371c9d4SSatish Balay static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd) {
48720a96aa3bSJed Brown   DM plex;
48730a96aa3bSJed Brown 
48740a96aa3bSJed Brown   PetscFunctionBegin;
48750a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48769566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48779566063dSJacob Faibussowitsch   PetscCall(DMGetDimPoints(plex, dim, cStart, cEnd));
48780a96aa3bSJed Brown   PetscFunctionReturn(0);
48790a96aa3bSJed Brown }
48800a96aa3bSJed Brown 
48810a96aa3bSJed Brown /* Need to forward declare */
48820a96aa3bSJed Brown #define DMInitialize_pforest _append_pforest(DMInitialize)
48830a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
48840a96aa3bSJed Brown 
48850a96aa3bSJed Brown #define DMClone_pforest _append_pforest(DMClone)
48869371c9d4SSatish Balay static PetscErrorCode DMClone_pforest(DM dm, DM *newdm) {
48870a96aa3bSJed Brown   PetscFunctionBegin;
48889566063dSJacob Faibussowitsch   PetscCall(DMClone_Forest(dm, newdm));
48899566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(*newdm));
48900a96aa3bSJed Brown   PetscFunctionReturn(0);
48910a96aa3bSJed Brown }
48920a96aa3bSJed Brown 
48930a96aa3bSJed Brown #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
48949371c9d4SSatish Balay static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd) {
48950a96aa3bSJed Brown   DM_Forest         *forest;
48960a96aa3bSJed Brown   DM_Forest_pforest *pforest;
48970a96aa3bSJed Brown   PetscInt           overlap;
48980a96aa3bSJed Brown 
48990a96aa3bSJed Brown   PetscFunctionBegin;
49009566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
49010a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
49020a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
49030a96aa3bSJed Brown   *cStart = 0;
49049566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
49050a96aa3bSJed Brown   if (overlap && pforest->ghost) {
49060a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
49070a96aa3bSJed Brown   } else {
49080a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
49090a96aa3bSJed Brown   }
49100a96aa3bSJed Brown   PetscFunctionReturn(0);
49110a96aa3bSJed Brown }
49120a96aa3bSJed Brown 
49130a96aa3bSJed Brown #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
49149371c9d4SSatish Balay static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF) {
49150a96aa3bSJed Brown   DM_Forest         *forest;
49160a96aa3bSJed Brown   DM_Forest_pforest *pforest;
49170a96aa3bSJed Brown   PetscMPIInt        rank;
49180a96aa3bSJed Brown   PetscInt           overlap;
49190a96aa3bSJed Brown   PetscInt           cStart, cEnd, cLocalStart, cLocalEnd;
49200a96aa3bSJed Brown   PetscInt           nRoots, nLeaves, *mine = NULL;
49210a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
49220a96aa3bSJed Brown   PetscSF            sf;
49230a96aa3bSJed Brown 
49240a96aa3bSJed Brown   PetscFunctionBegin;
49259566063dSJacob Faibussowitsch   PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
49260a96aa3bSJed Brown   forest      = (DM_Forest *)dm->data;
49270a96aa3bSJed Brown   pforest     = (DM_Forest_pforest *)forest->data;
49280a96aa3bSJed Brown   nRoots      = cEnd - cStart;
49290a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
49300a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
49310a96aa3bSJed Brown   nLeaves     = 0;
49329566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
49339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
49340a96aa3bSJed Brown   if (overlap && pforest->ghost) {
49350a96aa3bSJed Brown     PetscSFNode      *mirror;
49360a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
49370a96aa3bSJed Brown     PetscInt          nMirror, nGhostPre, nSelf, q;
49380a96aa3bSJed Brown     void            **mirrorPtrs;
49390a96aa3bSJed Brown 
49400a96aa3bSJed Brown     nMirror   = (PetscInt)pforest->ghost->mirrors.elem_count;
49410a96aa3bSJed Brown     nSelf     = cLocalEnd - cLocalStart;
49420a96aa3bSJed Brown     nLeaves   = nRoots - nSelf;
49430a96aa3bSJed Brown     nGhostPre = (PetscInt)pforest->ghost->proc_offsets[rank];
49449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &mine));
49459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &remote));
49469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nMirror, &mirror, nMirror, &mirrorPtrs));
49470a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t *)pforest->ghost->mirrors.array;
49480a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
49490a96aa3bSJed Brown       p4est_quadrant_t *mir = &(mirror_array[q]);
49500a96aa3bSJed Brown 
49510a96aa3bSJed Brown       mirror[q].rank  = rank;
49520a96aa3bSJed Brown       mirror[q].index = (PetscInt)mir->p.piggy3.local_num + cLocalStart;
49530a96aa3bSJed Brown       mirrorPtrs[q]   = (void *)&(mirror[q]);
49540a96aa3bSJed Brown     }
4955792fecdfSBarry Smith     PetscCallP4est(p4est_ghost_exchange_custom, (pforest->forest, pforest->ghost, sizeof(PetscSFNode), mirrorPtrs, remote));
49569566063dSJacob Faibussowitsch     PetscCall(PetscFree2(mirror, mirrorPtrs));
49570a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
49580a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
49590a96aa3bSJed Brown   }
49609566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &sf));
49619566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nRoots, nLeaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
49620a96aa3bSJed Brown   *cellSF = sf;
49630a96aa3bSJed Brown   PetscFunctionReturn(0);
49640a96aa3bSJed Brown }
49650a96aa3bSJed Brown 
49669371c9d4SSatish Balay static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS *ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void *), void **setup_ctx) {
49670a96aa3bSJed Brown   DM plex;
49680a96aa3bSJed Brown 
49690a96aa3bSJed Brown   PetscFunctionBegin;
49709566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49719566063dSJacob Faibussowitsch   PetscCall(DMCreateNeumannOverlap_Plex(plex, ovl, J, setup, setup_ctx));
49720a96aa3bSJed Brown   if (!*setup) {
49739566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
497448a46eb9SPierre Jolivet     if (*setup) PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
49750a96aa3bSJed Brown   }
49760a96aa3bSJed Brown   PetscFunctionReturn(0);
49770a96aa3bSJed Brown }
49780a96aa3bSJed Brown 
49799371c9d4SSatish Balay static PetscErrorCode DMInitialize_pforest(DM dm) {
49800a96aa3bSJed Brown   PetscFunctionBegin;
49810a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
49820a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
49830a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
49840a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
49850a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
49860a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
49870a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
49880a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
49890a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
49900a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
49910a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
49920a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
49930a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
49940a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
49950a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
49960a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
49970a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
49980a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
49990a96aa3bSJed Brown 
50009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_plex_pforest) "_C", DMConvert_plex_pforest));
50019566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_pforest_plex) "_C", DMConvert_pforest_plex));
50029566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_pforest));
50039566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMForestGetPartitionOverlap));
50040a96aa3bSJed Brown   PetscFunctionReturn(0);
50050a96aa3bSJed Brown }
50060a96aa3bSJed Brown 
50070a96aa3bSJed Brown #define DMCreate_pforest _append_pforest(DMCreate)
50089371c9d4SSatish Balay PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm) {
50090a96aa3bSJed Brown   DM_Forest         *forest;
50100a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50110a96aa3bSJed Brown 
50120a96aa3bSJed Brown   PetscFunctionBegin;
50139566063dSJacob Faibussowitsch   PetscCall(PetscP4estInitialize());
50149566063dSJacob Faibussowitsch   PetscCall(DMCreate_Forest(dm));
50159566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(dm));
50169566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, P4EST_DIM));
50170a96aa3bSJed Brown 
50180a96aa3bSJed Brown   /* set forest defaults */
50199566063dSJacob Faibussowitsch   PetscCall(DMForestSetTopology(dm, "unit"));
50209566063dSJacob Faibussowitsch   PetscCall(DMForestSetMinimumRefinement(dm, 0));
50219566063dSJacob Faibussowitsch   PetscCall(DMForestSetInitialRefinement(dm, 0));
50229566063dSJacob Faibussowitsch   PetscCall(DMForestSetMaximumRefinement(dm, P4EST_QMAXLEVEL));
50239566063dSJacob Faibussowitsch   PetscCall(DMForestSetGradeFactor(dm, 2));
50249566063dSJacob Faibussowitsch   PetscCall(DMForestSetAdjacencyDimension(dm, 0));
50259566063dSJacob Faibussowitsch   PetscCall(DMForestSetPartitionOverlap(dm, 0));
50260a96aa3bSJed Brown 
50270a96aa3bSJed Brown   /* create p4est data */
5028*4dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pforest));
50290a96aa3bSJed Brown 
50300a96aa3bSJed Brown   forest                            = (DM_Forest *)dm->data;
50310a96aa3bSJed Brown   forest->data                      = pforest;
50320a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
50330a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
50340a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
50350a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
50360a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
50370a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
50380a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
50390a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
50400a96aa3bSJed Brown   pforest->topo                     = NULL;
50410a96aa3bSJed Brown   pforest->forest                   = NULL;
50420a96aa3bSJed Brown   pforest->ghost                    = NULL;
50430a96aa3bSJed Brown   pforest->lnodes                   = NULL;
50440a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
50450a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
50460a96aa3bSJed Brown   pforest->cLocalStart              = -1;
50470a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
50480a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
50490a96aa3bSJed Brown   pforest->ghostName                = NULL;
50500a96aa3bSJed Brown   PetscFunctionReturn(0);
50510a96aa3bSJed Brown }
50520a96aa3bSJed Brown 
50530a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5054