xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 3ea99036a5fedea4d39e7e77471d0ab500c249d7)
1*3ea99036SJacob Faibussowitsch #ifndef PFOREST_H
2*3ea99036SJacob Faibussowitsch #define PFOREST_H
3*3ea99036SJacob Faibussowitsch 
40a96aa3bSJed Brown #include <petscds.h>
50a96aa3bSJed Brown #include <petsc/private/dmimpl.h>
60a96aa3bSJed Brown #include <petsc/private/dmforestimpl.h>
70a96aa3bSJed Brown #include <petsc/private/dmpleximpl.h>
80a96aa3bSJed Brown #include <petsc/private/dmlabelimpl.h>
90a96aa3bSJed Brown #include <petsc/private/viewerimpl.h>
100a96aa3bSJed Brown #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h>
110a96aa3bSJed Brown #include "petsc_p4est_package.h"
120a96aa3bSJed Brown 
130a96aa3bSJed Brown #if defined(PETSC_HAVE_P4EST)
140a96aa3bSJed Brown 
150a96aa3bSJed Brown   #if !defined(P4_TO_P8)
160a96aa3bSJed Brown     #include <p4est.h>
170a96aa3bSJed Brown     #include <p4est_extended.h>
180a96aa3bSJed Brown     #include <p4est_geometry.h>
190a96aa3bSJed Brown     #include <p4est_ghost.h>
200a96aa3bSJed Brown     #include <p4est_lnodes.h>
210a96aa3bSJed Brown     #include <p4est_vtk.h>
220a96aa3bSJed Brown     #include <p4est_plex.h>
230a96aa3bSJed Brown     #include <p4est_bits.h>
240a96aa3bSJed Brown     #include <p4est_algorithms.h>
250a96aa3bSJed Brown   #else
260a96aa3bSJed Brown     #include <p8est.h>
270a96aa3bSJed Brown     #include <p8est_extended.h>
280a96aa3bSJed Brown     #include <p8est_geometry.h>
290a96aa3bSJed Brown     #include <p8est_ghost.h>
300a96aa3bSJed Brown     #include <p8est_lnodes.h>
310a96aa3bSJed Brown     #include <p8est_vtk.h>
320a96aa3bSJed Brown     #include <p8est_plex.h>
330a96aa3bSJed Brown     #include <p8est_bits.h>
340a96aa3bSJed Brown     #include <p8est_algorithms.h>
350a96aa3bSJed Brown   #endif
360a96aa3bSJed Brown 
379371c9d4SSatish Balay typedef enum {
389371c9d4SSatish Balay   PATTERN_HASH,
399371c9d4SSatish Balay   PATTERN_FRACTAL,
409371c9d4SSatish Balay   PATTERN_CORNER,
419371c9d4SSatish Balay   PATTERN_CENTER,
429371c9d4SSatish Balay   PATTERN_COUNT
439371c9d4SSatish Balay } DMRefinePattern;
440a96aa3bSJed Brown static const char *DMRefinePatternName[PATTERN_COUNT] = {"hash", "fractal", "corner", "center"};
450a96aa3bSJed Brown 
469371c9d4SSatish Balay typedef struct _DMRefinePatternCtx {
470a96aa3bSJed Brown   PetscInt       corner;
480a96aa3bSJed Brown   PetscBool      fractal[P4EST_CHILDREN];
490a96aa3bSJed Brown   PetscReal      hashLikelihood;
500a96aa3bSJed Brown   PetscInt       maxLevel;
510a96aa3bSJed Brown   p4est_refine_t refine_fn;
529371c9d4SSatish Balay } DMRefinePatternCtx;
530a96aa3bSJed Brown 
54d71ae5a4SJacob Faibussowitsch static int DMRefinePattern_Corner(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
55d71ae5a4SJacob Faibussowitsch {
560a96aa3bSJed Brown   p4est_quadrant_t    root, rootcorner;
570a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
580a96aa3bSJed Brown 
590a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
600a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
610a96aa3bSJed Brown 
620a96aa3bSJed Brown   root.x = root.y = 0;
630a96aa3bSJed Brown   #if defined(P4_TO_P8)
640a96aa3bSJed Brown   root.z = 0;
650a96aa3bSJed Brown   #endif
660a96aa3bSJed Brown   root.level = 0;
670a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&root, &rootcorner, ctx->corner, quadrant->level);
680a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant, &rootcorner)) return 1;
690a96aa3bSJed Brown   return 0;
700a96aa3bSJed Brown }
710a96aa3bSJed Brown 
72d71ae5a4SJacob Faibussowitsch static int DMRefinePattern_Center(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
73d71ae5a4SJacob Faibussowitsch {
740a96aa3bSJed Brown   int                 cid;
750a96aa3bSJed Brown   p4est_quadrant_t    ancestor, ancestorcorner;
760a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
770a96aa3bSJed Brown 
780a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
790a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
800a96aa3bSJed Brown   if (quadrant->level <= 1) return 1;
810a96aa3bSJed Brown 
820a96aa3bSJed Brown   p4est_quadrant_ancestor(quadrant, 1, &ancestor);
830a96aa3bSJed Brown   cid = p4est_quadrant_child_id(&ancestor);
840a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&ancestor, &ancestorcorner, P4EST_CHILDREN - 1 - cid, quadrant->level);
850a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant, &ancestorcorner)) return 1;
860a96aa3bSJed Brown   return 0;
870a96aa3bSJed Brown }
880a96aa3bSJed Brown 
89d71ae5a4SJacob Faibussowitsch static int DMRefinePattern_Fractal(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
90d71ae5a4SJacob Faibussowitsch {
910a96aa3bSJed Brown   int                 cid;
920a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
930a96aa3bSJed Brown 
940a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
950a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
960a96aa3bSJed Brown   if (!quadrant->level) return 1;
970a96aa3bSJed Brown   cid = p4est_quadrant_child_id(quadrant);
980a96aa3bSJed Brown   if (ctx->fractal[cid ^ ((int)(quadrant->level % P4EST_CHILDREN))]) return 1;
990a96aa3bSJed Brown   return 0;
1000a96aa3bSJed Brown }
1010a96aa3bSJed Brown 
1020a96aa3bSJed Brown   /* simplified from MurmurHash3 by Austin Appleby */
1030a96aa3bSJed Brown   #define DMPROT32(x, y) ((x << y) | (x >> (32 - y)))
104d71ae5a4SJacob Faibussowitsch static uint32_t DMPforestHash(const uint32_t *blocks, uint32_t nblocks)
105d71ae5a4SJacob Faibussowitsch {
1060a96aa3bSJed Brown   uint32_t c1   = 0xcc9e2d51;
1070a96aa3bSJed Brown   uint32_t c2   = 0x1b873593;
1080a96aa3bSJed Brown   uint32_t r1   = 15;
1090a96aa3bSJed Brown   uint32_t r2   = 13;
1100a96aa3bSJed Brown   uint32_t m    = 5;
1110a96aa3bSJed Brown   uint32_t n    = 0xe6546b64;
1120a96aa3bSJed Brown   uint32_t hash = 0;
1130a96aa3bSJed Brown   int      len  = nblocks * 4;
1140a96aa3bSJed Brown   uint32_t i;
1150a96aa3bSJed Brown 
1160a96aa3bSJed Brown   for (i = 0; i < nblocks; i++) {
1170a96aa3bSJed Brown     uint32_t k;
1180a96aa3bSJed Brown 
1190a96aa3bSJed Brown     k = blocks[i];
1200a96aa3bSJed Brown     k *= c1;
1210a96aa3bSJed Brown     k = DMPROT32(k, r1);
1220a96aa3bSJed Brown     k *= c2;
1230a96aa3bSJed Brown 
1240a96aa3bSJed Brown     hash ^= k;
1250a96aa3bSJed Brown     hash = DMPROT32(hash, r2) * m + n;
1260a96aa3bSJed Brown   }
1270a96aa3bSJed Brown 
1280a96aa3bSJed Brown   hash ^= len;
1290a96aa3bSJed Brown   hash ^= (hash >> 16);
1300a96aa3bSJed Brown   hash *= 0x85ebca6b;
1310a96aa3bSJed Brown   hash ^= (hash >> 13);
1320a96aa3bSJed Brown   hash *= 0xc2b2ae35;
1330a96aa3bSJed Brown   hash ^= (hash >> 16);
1340a96aa3bSJed Brown 
1350a96aa3bSJed Brown   return hash;
1360a96aa3bSJed Brown }
1370a96aa3bSJed Brown 
1380a96aa3bSJed Brown   #if defined(UINT32_MAX)
1390a96aa3bSJed Brown     #define DMP4EST_HASH_MAX UINT32_MAX
1400a96aa3bSJed Brown   #else
1410a96aa3bSJed Brown     #define DMP4EST_HASH_MAX ((uint32_t)0xffffffff)
1420a96aa3bSJed Brown   #endif
1430a96aa3bSJed Brown 
144d71ae5a4SJacob Faibussowitsch static int DMRefinePattern_Hash(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
145d71ae5a4SJacob Faibussowitsch {
1460a96aa3bSJed Brown   uint32_t            data[5];
1470a96aa3bSJed Brown   uint32_t            result;
1480a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
1490a96aa3bSJed Brown 
1500a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
1510a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
1520a96aa3bSJed Brown   data[0] = ((uint32_t)quadrant->level) << 24;
1530a96aa3bSJed Brown   data[1] = (uint32_t)which_tree;
1540a96aa3bSJed Brown   data[2] = (uint32_t)quadrant->x;
1550a96aa3bSJed Brown   data[3] = (uint32_t)quadrant->y;
1560a96aa3bSJed Brown   #if defined(P4_TO_P8)
1570a96aa3bSJed Brown   data[4] = (uint32_t)quadrant->z;
1580a96aa3bSJed Brown   #endif
1590a96aa3bSJed Brown 
1600a96aa3bSJed Brown   result = DMPforestHash(data, 2 + P4EST_DIM);
1610a96aa3bSJed Brown   if (((double)result / (double)DMP4EST_HASH_MAX) < ctx->hashLikelihood) return 1;
1620a96aa3bSJed Brown   return 0;
1630a96aa3bSJed Brown }
1640a96aa3bSJed Brown 
1650a96aa3bSJed Brown   #define DMConvert_pforest_plex _infix_pforest(DMConvert, _plex)
1660a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM, DMType, DM *);
1670a96aa3bSJed Brown 
1680a96aa3bSJed Brown   #define DMFTopology_pforest _append_pforest(DMFTopology)
1690a96aa3bSJed Brown typedef struct {
1700a96aa3bSJed Brown   PetscInt              refct;
1710a96aa3bSJed Brown   p4est_connectivity_t *conn;
1720a96aa3bSJed Brown   p4est_geometry_t     *geom;
1730a96aa3bSJed Brown   PetscInt             *tree_face_to_uniq; /* p4est does not explicitly enumerate facets, but we must to keep track of labels */
1740a96aa3bSJed Brown } DMFTopology_pforest;
1750a96aa3bSJed Brown 
1760a96aa3bSJed Brown   #define DM_Forest_pforest _append_pforest(DM_Forest)
1770a96aa3bSJed Brown typedef struct {
1780a96aa3bSJed Brown   DMFTopology_pforest *topo;
1790a96aa3bSJed Brown   p4est_t             *forest;
1800a96aa3bSJed Brown   p4est_ghost_t       *ghost;
1810a96aa3bSJed Brown   p4est_lnodes_t      *lnodes;
1820a96aa3bSJed Brown   PetscBool            partition_for_coarsening;
1830a96aa3bSJed Brown   PetscBool            coarsen_hierarchy;
1840a96aa3bSJed Brown   PetscBool            labelsFinalized;
1850a96aa3bSJed Brown   PetscBool            adaptivitySuccess;
1860a96aa3bSJed Brown   PetscInt             cLocalStart;
1870a96aa3bSJed Brown   PetscInt             cLocalEnd;
1880a96aa3bSJed Brown   DM                   plex;
1890a96aa3bSJed Brown   char                *ghostName;
1900a96aa3bSJed Brown   PetscSF              pointAdaptToSelfSF;
1910a96aa3bSJed Brown   PetscSF              pointSelfToAdaptSF;
1920a96aa3bSJed Brown   PetscInt            *pointAdaptToSelfCids;
1930a96aa3bSJed Brown   PetscInt            *pointSelfToAdaptCids;
1940a96aa3bSJed Brown } DM_Forest_pforest;
1950a96aa3bSJed Brown 
1960a96aa3bSJed Brown   #define DM_Forest_geometry_pforest _append_pforest(DM_Forest_geometry)
1970a96aa3bSJed Brown typedef struct {
1980a96aa3bSJed Brown   DM base;
1990a96aa3bSJed Brown   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
2000a96aa3bSJed Brown   void             *mapCtx;
2010a96aa3bSJed Brown   PetscInt          coordDim;
2020a96aa3bSJed Brown   p4est_geometry_t *inner;
2039371c9d4SSatish Balay } DM_Forest_geometry_pforest;
2040a96aa3bSJed Brown 
2050a96aa3bSJed Brown   #define GeometryMapping_pforest _append_pforest(GeometryMapping)
206d71ae5a4SJacob Faibussowitsch static void GeometryMapping_pforest(p4est_geometry_t *geom, p4est_topidx_t which_tree, const double abc[3], double xyz[3])
207d71ae5a4SJacob Faibussowitsch {
2080a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest *)geom->user;
2090a96aa3bSJed Brown   PetscReal                   PetscABC[3]  = {0.};
2100a96aa3bSJed Brown   PetscReal                   PetscXYZ[3]  = {0.};
2110a96aa3bSJed Brown   PetscInt                    i, d = PetscMin(3, geom_pforest->coordDim);
2120a96aa3bSJed Brown   double                      ABC[3];
2130a96aa3bSJed Brown   PetscErrorCode              ierr;
2140a96aa3bSJed Brown 
2150a96aa3bSJed Brown   (geom_pforest->inner->X)(geom_pforest->inner, which_tree, abc, ABC);
2160a96aa3bSJed Brown 
2170a96aa3bSJed Brown   for (i = 0; i < d; i++) PetscABC[i] = ABC[i];
2189371c9d4SSatish Balay   ierr = (geom_pforest->map)(geom_pforest->base, (PetscInt)which_tree, geom_pforest->coordDim, PetscABC, PetscXYZ, geom_pforest->mapCtx);
2199371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2200a96aa3bSJed Brown   for (i = 0; i < d; i++) xyz[i] = PetscXYZ[i];
2210a96aa3bSJed Brown }
2220a96aa3bSJed Brown 
2230a96aa3bSJed Brown   #define GeometryDestroy_pforest _append_pforest(GeometryDestroy)
224d71ae5a4SJacob Faibussowitsch static void GeometryDestroy_pforest(p4est_geometry_t *geom)
225d71ae5a4SJacob Faibussowitsch {
2260a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest *)geom->user;
2270a96aa3bSJed Brown   PetscErrorCode              ierr;
2280a96aa3bSJed Brown 
2290a96aa3bSJed Brown   p4est_geometry_destroy(geom_pforest->inner);
2309371c9d4SSatish Balay   ierr = PetscFree(geom->user);
2319371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2329371c9d4SSatish Balay   ierr = PetscFree(geom);
2339371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2340a96aa3bSJed Brown }
2350a96aa3bSJed Brown 
2360a96aa3bSJed Brown   #define DMFTopologyDestroy_pforest _append_pforest(DMFTopologyDestroy)
237d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMFTopologyDestroy_pforest(DMFTopology_pforest **topo)
238d71ae5a4SJacob Faibussowitsch {
2390a96aa3bSJed Brown   PetscFunctionBegin;
2403ba16761SJacob Faibussowitsch   if (!(*topo)) PetscFunctionReturn(PETSC_SUCCESS);
2410a96aa3bSJed Brown   if (--((*topo)->refct) > 0) {
2420a96aa3bSJed Brown     *topo = NULL;
2433ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2440a96aa3bSJed Brown   }
245792fecdfSBarry Smith   if ((*topo)->geom) PetscCallP4est(p4est_geometry_destroy, ((*topo)->geom));
246792fecdfSBarry Smith   PetscCallP4est(p4est_connectivity_destroy, ((*topo)->conn));
2479566063dSJacob Faibussowitsch   PetscCall(PetscFree((*topo)->tree_face_to_uniq));
2489566063dSJacob Faibussowitsch   PetscCall(PetscFree(*topo));
2490a96aa3bSJed Brown   *topo = NULL;
2503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2510a96aa3bSJed Brown }
2520a96aa3bSJed Brown 
2530a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *, PetscInt **);
2540a96aa3bSJed Brown 
2550a96aa3bSJed Brown   #define DMFTopologyCreateBrick_pforest _append_pforest(DMFTopologyCreateBrick)
256d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMFTopologyCreateBrick_pforest(DM dm, PetscInt N[], PetscInt P[], PetscReal B[], DMFTopology_pforest **topo, PetscBool useMorton)
257d71ae5a4SJacob Faibussowitsch {
2580a96aa3bSJed Brown   double  *vertices;
2590a96aa3bSJed Brown   PetscInt i, numVerts;
2600a96aa3bSJed Brown 
2610a96aa3bSJed Brown   PetscFunctionBegin;
26228b400f6SJacob Faibussowitsch   PetscCheck(useMorton, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Lexicographic ordering not implemented yet");
2634dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(topo));
2640a96aa3bSJed Brown 
2650a96aa3bSJed Brown   (*topo)->refct = 1;
2660a96aa3bSJed Brown   #if !defined(P4_TO_P8)
267792fecdfSBarry 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));
2680a96aa3bSJed Brown   #else
269792fecdfSBarry 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));
2700a96aa3bSJed Brown   #endif
2710a96aa3bSJed Brown   numVerts = (*topo)->conn->num_vertices;
2720a96aa3bSJed Brown   vertices = (*topo)->conn->vertices;
2730a96aa3bSJed Brown   for (i = 0; i < 3 * numVerts; i++) {
2740a96aa3bSJed Brown     PetscInt j = i % 3;
2750a96aa3bSJed Brown 
2760a96aa3bSJed Brown     vertices[i] = B[2 * j] + (vertices[i] / N[j]) * (B[2 * j + 1] - B[2 * j]);
2770a96aa3bSJed Brown   }
2780a96aa3bSJed Brown   (*topo)->geom = NULL;
2799566063dSJacob Faibussowitsch   PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn, &(*topo)->tree_face_to_uniq));
2803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2810a96aa3bSJed Brown }
2820a96aa3bSJed Brown 
2830a96aa3bSJed Brown   #define DMFTopologyCreate_pforest _append_pforest(DMFTopologyCreate)
284d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMFTopologyCreate_pforest(DM dm, DMForestTopology topologyName, DMFTopology_pforest **topo)
285d71ae5a4SJacob Faibussowitsch {
2860a96aa3bSJed Brown   const char *name = (const char *)topologyName;
2870a96aa3bSJed Brown   const char *prefix;
2880a96aa3bSJed Brown   PetscBool   isBrick, isShell, isSphere, isMoebius;
2890a96aa3bSJed Brown 
2900a96aa3bSJed Brown   PetscFunctionBegin;
2910a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2924f572ea9SToby Isaac   PetscAssertPointer(name, 2);
2934f572ea9SToby Isaac   PetscAssertPointer(topo, 3);
2949566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "brick", &isBrick));
2959566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "shell", &isShell));
2969566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "sphere", &isSphere));
2979566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "moebius", &isMoebius));
2989566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2990a96aa3bSJed Brown   if (isBrick) {
3000a96aa3bSJed Brown     PetscBool flgN, flgP, flgM, flgB, useMorton = PETSC_TRUE, periodic = PETSC_FALSE;
3010a96aa3bSJed Brown     PetscInt  N[3] = {2, 2, 2}, P[3] = {0, 0, 0}, nretN = P4EST_DIM, nretP = P4EST_DIM, nretB = 2 * P4EST_DIM, i;
3024fb89dddSMatthew 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};
3030a96aa3bSJed Brown 
3040a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
3059566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_size", N, &nretN, &flgN));
3069566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_periodicity", P, &nretP, &flgP));
3079566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_bounds", B, &nretB, &flgB));
3089566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_use_morton_curve", &useMorton, &flgM));
3091dca8a05SBarry 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);
3101dca8a05SBarry 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);
3111dca8a05SBarry 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);
3120a96aa3bSJed Brown     }
3130a96aa3bSJed Brown     for (i = 0; i < P4EST_DIM; i++) {
3140a96aa3bSJed Brown       P[i]     = (P[i] ? DM_BOUNDARY_PERIODIC : DM_BOUNDARY_NONE);
3150a96aa3bSJed Brown       periodic = (PetscBool)(P[i] || periodic);
3160a96aa3bSJed Brown       if (!flgB) B[2 * i + 1] = N[i];
3176858538eSMatthew G. Knepley       if (P[i]) {
3184fb89dddSMatthew G. Knepley         Lstart[i]  = B[2 * i + 0];
3194fb89dddSMatthew G. Knepley         L[i]       = B[2 * i + 1] - B[2 * i + 0];
3206858538eSMatthew G. Knepley         maxCell[i] = 1.1 * (L[i] / N[i]);
3216858538eSMatthew G. Knepley       }
3220a96aa3bSJed Brown     }
3239566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreateBrick_pforest(dm, N, P, B, topo, useMorton));
3244fb89dddSMatthew G. Knepley     if (periodic) PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
3250a96aa3bSJed Brown   } else {
3264dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(topo));
3270a96aa3bSJed Brown 
3280a96aa3bSJed Brown     (*topo)->refct = 1;
329792fecdfSBarry Smith     PetscCallP4estReturn((*topo)->conn, p4est_connectivity_new_byname, (name));
3300a96aa3bSJed Brown     (*topo)->geom = NULL;
3311baa6e33SBarry Smith     if (isMoebius) PetscCall(DMSetCoordinateDim(dm, 3));
3320a96aa3bSJed Brown   #if defined(P4_TO_P8)
3330a96aa3bSJed Brown     if (isShell) {
3340a96aa3bSJed Brown       PetscReal R2 = 1., R1 = .55;
3350a96aa3bSJed Brown 
3360a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3379566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_shell_outer_radius", &R2, NULL));
3389566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_shell_inner_radius", &R1, NULL));
3390a96aa3bSJed Brown       }
340792fecdfSBarry Smith       PetscCallP4estReturn((*topo)->geom, p8est_geometry_new_shell, ((*topo)->conn, R2, R1));
3410a96aa3bSJed Brown     } else if (isSphere) {
3420a96aa3bSJed Brown       PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856;
3430a96aa3bSJed Brown 
3440a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3459566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_outer_radius", &R2, NULL));
3469566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_inner_radius", &R1, NULL));
3479566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_core_radius", &R0, NULL));
3480a96aa3bSJed Brown       }
349792fecdfSBarry Smith       PetscCallP4estReturn((*topo)->geom, p8est_geometry_new_sphere, ((*topo)->conn, R2, R1, R0));
3500a96aa3bSJed Brown     }
3510a96aa3bSJed Brown   #endif
3529566063dSJacob Faibussowitsch     PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn, &(*topo)->tree_face_to_uniq));
3530a96aa3bSJed Brown   }
3543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3550a96aa3bSJed Brown }
3560a96aa3bSJed Brown 
3570a96aa3bSJed Brown   #define DMConvert_plex_pforest _append_pforest(DMConvert_plex)
358d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest)
359d71ae5a4SJacob Faibussowitsch {
3600a96aa3bSJed Brown   MPI_Comm  comm;
3610a96aa3bSJed Brown   PetscBool isPlex;
3620a96aa3bSJed Brown   PetscInt  dim;
3630a96aa3bSJed Brown   void     *ctx;
3640a96aa3bSJed Brown 
3650a96aa3bSJed Brown   PetscFunctionBegin;
3660a96aa3bSJed Brown 
3670a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3680a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
3699566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
37028b400f6SJacob Faibussowitsch   PetscCheck(isPlex, comm, PETSC_ERR_ARG_WRONG, "Expected DM type %s, got %s", DMPLEX, ((PetscObject)dm)->type_name);
3719566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
37263a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Expected DM dimension %d, got %" PetscInt_FMT, P4EST_DIM, dim);
3739566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, pforest));
3749566063dSJacob Faibussowitsch   PetscCall(DMSetType(*pforest, DMPFOREST));
3759566063dSJacob Faibussowitsch   PetscCall(DMForestSetBaseDM(*pforest, dm));
3769566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dm, &ctx));
3779566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(*pforest, ctx));
3789566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *pforest));
3793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3800a96aa3bSJed Brown }
3810a96aa3bSJed Brown 
3820a96aa3bSJed Brown   #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
383d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestDestroy_pforest(DM dm)
384d71ae5a4SJacob Faibussowitsch {
3850a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
3860a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
3870a96aa3bSJed Brown 
3880a96aa3bSJed Brown   PetscFunctionBegin;
3890a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
390792fecdfSBarry Smith   if (pforest->lnodes) PetscCallP4est(p4est_lnodes_destroy, (pforest->lnodes));
3910a96aa3bSJed Brown   pforest->lnodes = NULL;
392792fecdfSBarry Smith   if (pforest->ghost) PetscCallP4est(p4est_ghost_destroy, (pforest->ghost));
3930a96aa3bSJed Brown   pforest->ghost = NULL;
394792fecdfSBarry Smith   if (pforest->forest) PetscCallP4est(p4est_destroy, (pforest->forest));
3950a96aa3bSJed Brown   pforest->forest = NULL;
3969566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&pforest->topo));
3979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_plex_pforest) "_C", NULL));
3989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_pforest_plex) "_C", NULL));
3992e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
4009566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
4012e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
4022e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
4039566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->ghostName));
4049566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&pforest->plex));
4059566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
4069566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
4079566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
4089566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
4099566063dSJacob Faibussowitsch   PetscCall(PetscFree(forest->data));
4103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4110a96aa3bSJed Brown }
4120a96aa3bSJed Brown 
4130a96aa3bSJed Brown   #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
414d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm)
415d71ae5a4SJacob Faibussowitsch {
4160a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
4170a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest *)((DM_Forest *)tdm->data)->data;
4180a96aa3bSJed Brown 
4190a96aa3bSJed Brown   PetscFunctionBegin;
4200a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
4219566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&(tpforest->topo)));
4220a96aa3bSJed Brown   tpforest->topo = pforest->topo;
4233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4240a96aa3bSJed Brown }
4250a96aa3bSJed Brown 
4260a96aa3bSJed Brown   #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
4270a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM, p4est_connectivity_t **, PetscInt **);
4280a96aa3bSJed Brown 
4299371c9d4SSatish Balay typedef struct _PforestAdaptCtx {
4300a96aa3bSJed Brown   PetscInt  maxLevel;
4310a96aa3bSJed Brown   PetscInt  minLevel;
4320a96aa3bSJed Brown   PetscInt  currLevel;
4330a96aa3bSJed Brown   PetscBool anyChange;
4349371c9d4SSatish Balay } PforestAdaptCtx;
4350a96aa3bSJed Brown 
436d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_currlevel(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
437d71ae5a4SJacob Faibussowitsch {
4380a96aa3bSJed Brown   PforestAdaptCtx *ctx       = (PforestAdaptCtx *)p4est->user_pointer;
4390a96aa3bSJed Brown   PetscInt         minLevel  = ctx->minLevel;
4400a96aa3bSJed Brown   PetscInt         currLevel = ctx->currLevel;
4410a96aa3bSJed Brown 
4420a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4430a96aa3bSJed Brown   return (int)((PetscInt)quadrants[0]->level == currLevel);
4440a96aa3bSJed Brown }
4450a96aa3bSJed Brown 
446d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_uniform(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
447d71ae5a4SJacob Faibussowitsch {
4480a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4490a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4500a96aa3bSJed Brown 
4510a96aa3bSJed Brown   return (int)((PetscInt)quadrants[0]->level > minLevel);
4520a96aa3bSJed Brown }
4530a96aa3bSJed Brown 
454d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_flag_any(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
455d71ae5a4SJacob Faibussowitsch {
4560a96aa3bSJed Brown   PetscInt         i;
4570a96aa3bSJed Brown   PetscBool        any      = PETSC_FALSE;
4580a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4590a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4600a96aa3bSJed Brown 
4610a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4620a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4630a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
4640a96aa3bSJed Brown       any = PETSC_FALSE;
4650a96aa3bSJed Brown       break;
4660a96aa3bSJed Brown     }
4670a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
4680a96aa3bSJed Brown       any = PETSC_TRUE;
4690a96aa3bSJed Brown       break;
4700a96aa3bSJed Brown     }
4710a96aa3bSJed Brown   }
4720a96aa3bSJed Brown   return any ? 1 : 0;
4730a96aa3bSJed Brown }
4740a96aa3bSJed Brown 
475d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_flag_all(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
476d71ae5a4SJacob Faibussowitsch {
4770a96aa3bSJed Brown   PetscInt         i;
4780a96aa3bSJed Brown   PetscBool        all      = PETSC_TRUE;
4790a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4800a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4810a96aa3bSJed Brown 
4820a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4830a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4840a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
4850a96aa3bSJed Brown       all = PETSC_FALSE;
4860a96aa3bSJed Brown       break;
4870a96aa3bSJed Brown     }
4880a96aa3bSJed Brown   }
4890a96aa3bSJed Brown   return all ? 1 : 0;
4900a96aa3bSJed Brown }
4910a96aa3bSJed Brown 
492d71ae5a4SJacob Faibussowitsch static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
493d71ae5a4SJacob Faibussowitsch {
4940a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
4950a96aa3bSJed Brown }
4960a96aa3bSJed Brown 
497d71ae5a4SJacob Faibussowitsch static int pforest_refine_uniform(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
498d71ae5a4SJacob Faibussowitsch {
4990a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
5000a96aa3bSJed Brown   PetscInt         maxLevel = ctx->maxLevel;
5010a96aa3bSJed Brown 
5020a96aa3bSJed Brown   return ((PetscInt)quadrant->level < maxLevel);
5030a96aa3bSJed Brown }
5040a96aa3bSJed Brown 
505d71ae5a4SJacob Faibussowitsch static int pforest_refine_flag(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
506d71ae5a4SJacob Faibussowitsch {
5070a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
5080a96aa3bSJed Brown   PetscInt         maxLevel = ctx->maxLevel;
5090a96aa3bSJed Brown 
5100a96aa3bSJed Brown   if ((PetscInt)quadrant->level >= maxLevel) return 0;
5110a96aa3bSJed Brown 
5120a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
5130a96aa3bSJed Brown }
5140a96aa3bSJed Brown 
515d71ae5a4SJacob Faibussowitsch 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)
516d71ae5a4SJacob Faibussowitsch {
5170a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
5180a96aa3bSJed Brown   p4est_topidx_t t;
5190a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
5200a96aa3bSJed Brown 
5210a96aa3bSJed Brown   PetscFunctionBegin;
5220a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
5230a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t *)p4estFrom->trees->array)[t]);
5240a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t *)p4estTo->trees->array)[t]);
5250a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
5260a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
5270a96aa3bSJed Brown     PetscInt          numFrom   = (PetscInt)treeFrom->quadrants.elem_count;
5280a96aa3bSJed Brown     PetscInt          numTo     = (PetscInt)treeTo->quadrants.elem_count;
5290a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t *)treeFrom->quadrants.array;
5300a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t *)treeTo->quadrants.array;
5310a96aa3bSJed Brown     PetscInt          currentFrom, currentTo;
5320a96aa3bSJed Brown     PetscInt          treeOffsetFrom = (PetscInt)treeFrom->quadrants_offset;
5330a96aa3bSJed Brown     PetscInt          treeOffsetTo   = (PetscInt)treeTo->quadrants_offset;
5340a96aa3bSJed Brown     int               comp;
5350a96aa3bSJed Brown 
536792fecdfSBarry Smith     PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (firstFrom, firstTo));
53728b400f6SJacob Faibussowitsch     PetscCheck(comp, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "non-matching partitions");
5380a96aa3bSJed Brown 
5390a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
5400a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
5410a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
5420a96aa3bSJed Brown 
5430a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
5440a96aa3bSJed Brown         if (toLeaves) {
5450a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5460a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
5470a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5480a96aa3bSJed Brown         }
5490a96aa3bSJed Brown         toFineLeaves++;
5500a96aa3bSJed Brown         currentFrom++;
5510a96aa3bSJed Brown         currentTo++;
5520a96aa3bSJed Brown       } else {
5530a96aa3bSJed Brown         int fromIsAncestor;
5540a96aa3bSJed Brown 
555792fecdfSBarry Smith         PetscCallP4estReturn(fromIsAncestor, p4est_quadrant_is_ancestor, (quadFrom, quadTo));
5560a96aa3bSJed Brown         if (fromIsAncestor) {
5570a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5580a96aa3bSJed Brown 
5590a96aa3bSJed Brown           if (toLeaves) {
5600a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5610a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
5620a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5630a96aa3bSJed Brown           }
5640a96aa3bSJed Brown           toFineLeaves++;
5650a96aa3bSJed Brown           currentTo++;
566792fecdfSBarry Smith           PetscCallP4est(p4est_quadrant_last_descendant, (quadFrom, &lastDesc, quadTo->level));
567792fecdfSBarry Smith           PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (quadTo, &lastDesc));
5680a96aa3bSJed Brown           if (comp) currentFrom++;
5690a96aa3bSJed Brown         } else {
5700a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5710a96aa3bSJed Brown 
5720a96aa3bSJed Brown           if (fromLeaves) {
5730a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
5740a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
5750a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
5760a96aa3bSJed Brown           }
5770a96aa3bSJed Brown           fromFineLeaves++;
5780a96aa3bSJed Brown           currentFrom++;
579792fecdfSBarry Smith           PetscCallP4est(p4est_quadrant_last_descendant, (quadTo, &lastDesc, quadFrom->level));
580792fecdfSBarry Smith           PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (quadFrom, &lastDesc));
5810a96aa3bSJed Brown           if (comp) currentTo++;
5820a96aa3bSJed Brown         }
5830a96aa3bSJed Brown       }
5840a96aa3bSJed Brown     }
5850a96aa3bSJed Brown   }
5860a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
5870a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
5883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5890a96aa3bSJed Brown }
5900a96aa3bSJed Brown 
5910a96aa3bSJed Brown /* Compute the maximum level across all the trees */
592d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev)
593d71ae5a4SJacob Faibussowitsch {
5940a96aa3bSJed Brown   p4est_topidx_t     t, flt, llt;
5950a96aa3bSJed Brown   DM_Forest         *forest      = (DM_Forest *)dm->data;
5960a96aa3bSJed Brown   DM_Forest_pforest *pforest     = (DM_Forest_pforest *)forest->data;
5970a96aa3bSJed Brown   PetscInt           maxlevelloc = 0;
5980a96aa3bSJed Brown   p4est_t           *p4est;
5990a96aa3bSJed Brown 
6000a96aa3bSJed Brown   PetscFunctionBegin;
60128b400f6SJacob Faibussowitsch   PetscCheck(pforest, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing DM_Forest_pforest");
60228b400f6SJacob Faibussowitsch   PetscCheck(pforest->forest, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing p4est_t");
6030a96aa3bSJed Brown   p4est = pforest->forest;
6040a96aa3bSJed Brown   flt   = p4est->first_local_tree;
6050a96aa3bSJed Brown   llt   = p4est->last_local_tree;
6060a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
6070a96aa3bSJed Brown     p4est_tree_t *tree = &(((p4est_tree_t *)p4est->trees->array)[t]);
6080a96aa3bSJed Brown     maxlevelloc        = PetscMax((PetscInt)tree->maxlevel, maxlevelloc);
6090a96aa3bSJed Brown   }
6101c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&maxlevelloc, lev, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
6113ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6120a96aa3bSJed Brown }
6130a96aa3bSJed Brown 
6140a96aa3bSJed Brown /* Puts identity in coarseToFine */
6150a96aa3bSJed Brown /* assumes a matching partition */
616d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine)
617d71ae5a4SJacob Faibussowitsch {
6180a96aa3bSJed Brown   p4est_topidx_t flt, llt;
6190a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
6200a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
6210a96aa3bSJed Brown   PetscInt      *fromLeaves = NULL, *toLeaves = NULL;
6220a96aa3bSJed Brown   PetscSFNode   *fromRoots = NULL, *toRoots = NULL;
6230a96aa3bSJed Brown 
6240a96aa3bSJed Brown   PetscFunctionBegin;
6250a96aa3bSJed Brown   flt = p4estFrom->first_local_tree;
6260a96aa3bSJed Brown   llt = p4estFrom->last_local_tree;
6279566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &fromCoarse));
62848a46eb9SPierre Jolivet   if (toCoarseFromFine) PetscCall(PetscSFCreate(comm, &toCoarse));
6290a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
6300a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
6319566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom, FromOffset, p4estTo, ToOffset, flt, llt, &numLeavesTo, NULL, NULL, &numLeavesFrom, NULL, NULL));
6329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo, &toLeaves));
6339566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo, &fromRoots));
6340a96aa3bSJed Brown   if (toCoarseFromFine) {
6359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom, &fromLeaves));
6369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom, &fromRoots));
6370a96aa3bSJed Brown   }
6389566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom, FromOffset, p4estTo, ToOffset, flt, llt, &numLeavesTo, toLeaves, fromRoots, &numLeavesFrom, fromLeaves, toRoots));
6390a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
6409566063dSJacob Faibussowitsch     PetscCall(PetscFree(toLeaves));
6419566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(fromCoarse, numRootsFrom, numLeavesTo, NULL, PETSC_OWN_POINTER, fromRoots, PETSC_OWN_POINTER));
6421baa6e33SBarry Smith   } else PetscCall(PetscSFSetGraph(fromCoarse, numRootsFrom, numLeavesTo, toLeaves, PETSC_OWN_POINTER, fromRoots, PETSC_OWN_POINTER));
6430a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
6440a96aa3bSJed Brown   if (toCoarseFromFine) {
6459566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(toCoarse, numRootsTo, numLeavesFrom, fromLeaves, PETSC_OWN_POINTER, toRoots, PETSC_OWN_POINTER));
6460a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
6470a96aa3bSJed Brown   }
6483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6490a96aa3bSJed Brown }
6500a96aa3bSJed Brown 
6510a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
652d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB)
653d71ae5a4SJacob Faibussowitsch {
6540a96aa3bSJed Brown   p4est_quadrant_t *myCoarseStart = &(p4estA->global_first_position[rank]);
6550a96aa3bSJed Brown   p4est_quadrant_t *myCoarseEnd   = &(p4estA->global_first_position[rank + 1]);
6560a96aa3bSJed Brown   p4est_quadrant_t *globalFirstB  = p4estB->global_first_position;
6570a96aa3bSJed Brown 
6580a96aa3bSJed Brown   PetscFunctionBegin;
6590a96aa3bSJed Brown   *startB = -1;
6600a96aa3bSJed Brown   *endB   = -1;
6610a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
6620a96aa3bSJed Brown     PetscInt lo, hi, guess;
6630a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
6640a96aa3bSJed Brown     lo    = 0;
6650a96aa3bSJed Brown     hi    = size;
6660a96aa3bSJed Brown     guess = rank;
6670a96aa3bSJed Brown     while (1) {
6680a96aa3bSJed Brown       int startCompMy, myCompEnd;
6690a96aa3bSJed Brown 
670792fecdfSBarry Smith       PetscCallP4estReturn(startCompMy, p4est_quadrant_compare_piggy, (&globalFirstB[guess], myCoarseStart));
671792fecdfSBarry Smith       PetscCallP4estReturn(myCompEnd, p4est_quadrant_compare_piggy, (myCoarseStart, &globalFirstB[guess + 1]));
6720a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
6730a96aa3bSJed Brown         *startB = guess;
6740a96aa3bSJed Brown         break;
6750a96aa3bSJed Brown       } else if (startCompMy > 0) { /* guess is to high */
6760a96aa3bSJed Brown         hi = guess;
6770a96aa3bSJed Brown       } else { /* guess is to low */
6780a96aa3bSJed Brown         lo = guess + 1;
6790a96aa3bSJed Brown       }
6800a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6810a96aa3bSJed Brown     }
6820a96aa3bSJed Brown     /* reset bounds, but not guess */
6830a96aa3bSJed Brown     lo = 0;
6840a96aa3bSJed Brown     hi = size;
6850a96aa3bSJed Brown     while (1) {
6860a96aa3bSJed Brown       int startCompMy, myCompEnd;
6870a96aa3bSJed Brown 
688792fecdfSBarry Smith       PetscCallP4estReturn(startCompMy, p4est_quadrant_compare_piggy, (&globalFirstB[guess], myCoarseEnd));
689792fecdfSBarry Smith       PetscCallP4estReturn(myCompEnd, p4est_quadrant_compare_piggy, (myCoarseEnd, &globalFirstB[guess + 1]));
6900a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
6910a96aa3bSJed Brown         *endB = guess + 1;
6920a96aa3bSJed Brown         break;
6930a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
6940a96aa3bSJed Brown         hi = guess;
6950a96aa3bSJed Brown       } else { /* guess is to low */
6960a96aa3bSJed Brown         lo = guess + 1;
6970a96aa3bSJed Brown       }
6980a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6990a96aa3bSJed Brown     }
7000a96aa3bSJed Brown   }
7013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7020a96aa3bSJed Brown }
7030a96aa3bSJed Brown 
7040a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM, DM *);
7050a96aa3bSJed Brown 
7060a96aa3bSJed Brown   #define DMSetUp_pforest _append_pforest(DMSetUp)
707d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSetUp_pforest(DM dm)
708d71ae5a4SJacob Faibussowitsch {
7090a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
7100a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
7110a96aa3bSJed Brown   DM                 base, adaptFrom;
7120a96aa3bSJed Brown   DMForestTopology   topoName;
7130a96aa3bSJed Brown   PetscSF            preCoarseToFine = NULL, coarseToPreFine = NULL;
7140a96aa3bSJed Brown   PforestAdaptCtx    ctx;
7150a96aa3bSJed Brown 
7160a96aa3bSJed Brown   PetscFunctionBegin;
7170a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
7180a96aa3bSJed Brown   ctx.maxLevel  = 0;
7190a96aa3bSJed Brown   ctx.currLevel = 0;
7200a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
7210a96aa3bSJed Brown   /* sanity check */
7229566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm, &adaptFrom));
7239566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
7249566063dSJacob Faibussowitsch   PetscCall(DMForestGetTopology(dm, &topoName));
7251dca8a05SBarry 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");
7260a96aa3bSJed Brown 
7270a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
7280a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
7290a96aa3bSJed Brown     PetscBool          ispforest;
7300a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest *)adaptFrom->data;
7310a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest *)aforest->data;
7320a96aa3bSJed Brown 
7339566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)adaptFrom, DMPFOREST, &ispforest));
73428b400f6SJacob Faibussowitsch     PetscCheck(ispforest, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NOTSAMETYPE, "Trying to adapt from %s, which is not %s", ((PetscObject)adaptFrom)->type_name, DMPFOREST);
73528b400f6SJacob Faibussowitsch     PetscCheck(apforest->topo, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "The pre-adaptation forest must have a topology");
7369566063dSJacob Faibussowitsch     PetscCall(DMSetUp(adaptFrom));
7379566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm, &base));
7389566063dSJacob Faibussowitsch     PetscCall(DMForestGetTopology(dm, &topoName));
7390a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
7400a96aa3bSJed Brown     PetscBool isPlex, isDA;
7410a96aa3bSJed Brown 
7429566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)base, &topoName));
7439566063dSJacob Faibussowitsch     PetscCall(DMForestSetTopology(dm, topoName));
7449566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base, DMPLEX, &isPlex));
7459566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base, DMDA, &isDA));
7460a96aa3bSJed Brown     if (isPlex) {
7470a96aa3bSJed Brown       MPI_Comm              comm = PetscObjectComm((PetscObject)dm);
7480a96aa3bSJed Brown       PetscInt              depth;
7490a96aa3bSJed Brown       PetscMPIInt           size;
7500a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
7510a96aa3bSJed Brown       DMFTopology_pforest  *topo;
7520a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
7530a96aa3bSJed Brown 
7549566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepth(base, &depth));
7550a96aa3bSJed Brown       if (depth == 1) {
7560a96aa3bSJed Brown         DM connDM;
7570a96aa3bSJed Brown 
7589566063dSJacob Faibussowitsch         PetscCall(DMPlexInterpolate(base, &connDM));
7590a96aa3bSJed Brown         base = connDM;
7609566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm, base));
7619566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&connDM));
76263a3b9bcSJacob 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);
7639566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(comm, &size));
7640a96aa3bSJed Brown       if (size > 1) {
7650a96aa3bSJed Brown         DM      dmRedundant;
7660a96aa3bSJed Brown         PetscSF sf;
7670a96aa3bSJed Brown 
7689566063dSJacob Faibussowitsch         PetscCall(DMPlexGetRedundantDM(base, &sf, &dmRedundant));
76928b400f6SJacob Faibussowitsch         PetscCheck(dmRedundant, comm, PETSC_ERR_PLIB, "Could not create redundant DM");
7709566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)dmRedundant, "_base_migration_sf", (PetscObject)sf));
7719566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&sf));
7720a96aa3bSJed Brown         base = dmRedundant;
7739566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm, base));
7749566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&dmRedundant));
7750a96aa3bSJed Brown       }
7769566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(base, NULL, "-dm_p4est_base_view"));
7779566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateConnectivity_pforest(base, &conn, &tree_face_to_uniq));
7784dfa11a4SJacob Faibussowitsch       PetscCall(PetscNew(&topo));
7790a96aa3bSJed Brown       topo->refct = 1;
7800a96aa3bSJed Brown       topo->conn  = conn;
7810a96aa3bSJed Brown       topo->geom  = NULL;
7820a96aa3bSJed Brown       {
7830a96aa3bSJed Brown         PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
7840a96aa3bSJed Brown         void *mapCtx;
7850a96aa3bSJed Brown 
7869566063dSJacob Faibussowitsch         PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
7870a96aa3bSJed Brown         if (map) {
7880a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
7890a96aa3bSJed Brown           p4est_geometry_t           *geom;
7900a96aa3bSJed Brown 
7919566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom_pforest));
7929566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinateDim(dm, &geom_pforest->coordDim));
7930a96aa3bSJed Brown           geom_pforest->map    = map;
7940a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
795792fecdfSBarry Smith           PetscCallP4estReturn(geom_pforest->inner, p4est_geometry_new_connectivity, (conn));
7969566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom));
7970a96aa3bSJed Brown           geom->name    = topoName;
7980a96aa3bSJed Brown           geom->user    = geom_pforest;
7990a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
8000a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
8010a96aa3bSJed Brown           topo->geom    = geom;
8020a96aa3bSJed Brown         }
8030a96aa3bSJed Brown       }
8040a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
8050a96aa3bSJed Brown       pforest->topo           = topo;
80628b400f6SJacob Faibussowitsch     } else PetscCheck(!isDA, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Not implemented yet");
8070a96aa3bSJed Brown   #if 0
8080a96aa3bSJed Brown       PetscInt N[3], P[3];
8090a96aa3bSJed Brown 
8100a96aa3bSJed Brown       /* get the sizes, periodicities */
8110a96aa3bSJed Brown       /* ... */
8120a96aa3bSJed Brown                                                                   /* don't use Morton order */
8139566063dSJacob Faibussowitsch       PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE));
8140a96aa3bSJed Brown   #endif
8150a96aa3bSJed Brown     {
8160a96aa3bSJed Brown       PetscInt numLabels, l;
8170a96aa3bSJed Brown 
8189566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(base, &numLabels));
8190a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
8200a96aa3bSJed Brown         PetscBool   isDepth, isGhost, isVTK, isDim, isCellType;
8210a96aa3bSJed Brown         DMLabel     label, labelNew;
8220a96aa3bSJed Brown         PetscInt    defVal;
8230a96aa3bSJed Brown         const char *name;
8240a96aa3bSJed Brown 
8259566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(base, l, &name));
8269566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(base, l, &label));
8279566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "depth", &isDepth));
8280a96aa3bSJed Brown         if (isDepth) continue;
8299566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "dim", &isDim));
8300a96aa3bSJed Brown         if (isDim) continue;
8319566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "celltype", &isCellType));
8320a96aa3bSJed Brown         if (isCellType) continue;
8339566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "ghost", &isGhost));
8340a96aa3bSJed Brown         if (isGhost) continue;
8359566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "vtk", &isVTK));
8360a96aa3bSJed Brown         if (isVTK) continue;
8379566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm, name));
8389566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm, name, &labelNew));
8399566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label, &defVal));
8409566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
8410a96aa3bSJed Brown       }
8420a96aa3bSJed Brown       /* map dm points (internal plex) to base
8430a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
8440a96aa3bSJed Brown          and propagating back to the coarsest
8450a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
8460a96aa3bSJed Brown          during DMForestTransferVecFromBase */
8479566063dSJacob Faibussowitsch       PetscCall(DMForestGetMinimumRefinement(dm, &l));
84848a46eb9SPierre Jolivet       if (!l) PetscCall(DMCreateLabel(dm, "_forest_base_subpoint_map"));
8490a96aa3bSJed Brown     }
8500a96aa3bSJed Brown   } else { /* construct from topology name */
8510a96aa3bSJed Brown     DMFTopology_pforest *topo;
8520a96aa3bSJed Brown 
8539566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreate_pforest(dm, topoName, &topo));
8540a96aa3bSJed Brown     pforest->topo = topo;
8550a96aa3bSJed Brown     /* TODO: construct base? */
8560a96aa3bSJed Brown   }
8570a96aa3bSJed Brown 
8580a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
8590a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
8600a96aa3bSJed Brown     DMLabel            adaptLabel;
8610a96aa3bSJed Brown     PetscInt           defaultValue;
8620a96aa3bSJed Brown     PetscInt           numValues, numValuesGlobal, cLocalStart, count;
8630a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest *)adaptFrom->data;
8640a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest *)aforest->data;
8650a96aa3bSJed Brown     PetscBool          computeAdaptSF;
8660a96aa3bSJed Brown     p4est_topidx_t     flt, llt, t;
8670a96aa3bSJed Brown 
8680a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
8690a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
8700a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
8719566063dSJacob Faibussowitsch     PetscCall(DMForestGetComputeAdaptivitySF(dm, &computeAdaptSF));
872792fecdfSBarry Smith     PetscCallP4estReturn(pforest->forest, p4est_copy, (apforest->forest, 0)); /* 0 indicates no data copying */
8739566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm, &adaptLabel));
8740a96aa3bSJed Brown     if (adaptLabel) {
8750a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
8769566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(adaptLabel, &numValues));
877712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&numValues, &numValuesGlobal, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)adaptFrom)));
8789566063dSJacob Faibussowitsch       PetscCall(DMLabelGetDefaultValue(adaptLabel, &defaultValue));
8790a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
8809566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8819566063dSJacob Faibussowitsch         PetscCall(DMPforestGetRefinementLevel(dm, &ctx.currLevel));
8820a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
883792fecdfSBarry Smith         PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_currlevel, NULL));
8840a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
885792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8860a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
88748a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), pforest->forest, 0, apforest->forest, apforest->cLocalStart, &coarseToPreFine, NULL));
8880a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */
8899566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8900a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
891792fecdfSBarry Smith         PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_uniform, NULL));
8920a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
893792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8940a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
89548a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), pforest->forest, 0, apforest->forest, apforest->cLocalStart, &coarseToPreFine, NULL));
8960a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
8979566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &ctx.maxLevel));
8980a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
899792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 0, pforest_refine_uniform, NULL));
9000a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
901792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
9020a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
90348a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), apforest->forest, apforest->cLocalStart, pforest->forest, 0, &preCoarseToFine, NULL));
9040a96aa3bSJed Brown       } else if (numValuesGlobal) {
9050a96aa3bSJed Brown         p4est_t                   *p4est = pforest->forest;
9060a96aa3bSJed Brown         PetscInt                  *cellFlags;
9070a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
9080a96aa3bSJed Brown         PetscSF                    cellSF;
9090a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
9100a96aa3bSJed Brown         PetscBool                  adaptAny;
9110a96aa3bSJed Brown 
9129566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &ctx.maxLevel));
9139566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
9149566063dSJacob Faibussowitsch         PetscCall(DMForestGetAdaptivityStrategy(dm, &strategy));
9159566063dSJacob Faibussowitsch         PetscCall(PetscStrncmp(strategy, "any", 3, &adaptAny));
9169566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellChart(adaptFrom, &cStart, &cEnd));
9179566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellSF(adaptFrom, &cellSF));
9189566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cEnd - cStart, &cellFlags));
9199566063dSJacob Faibussowitsch         for (c = cStart; c < cEnd; c++) PetscCall(DMLabelGetValue(adaptLabel, c, &cellFlags[c - cStart]));
9200a96aa3bSJed Brown         if (cellSF) {
9210a96aa3bSJed Brown           if (adaptAny) {
9229566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MAX));
9239566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MAX));
9240a96aa3bSJed Brown           } else {
9259566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MIN));
9269566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MIN));
9270a96aa3bSJed Brown           }
9280a96aa3bSJed Brown         }
9290a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
9300a96aa3bSJed Brown           p4est_tree_t     *tree     = &(((p4est_tree_t *)p4est->trees->array)[t]);
9310a96aa3bSJed Brown           PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count, i;
9320a96aa3bSJed Brown           p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
9330a96aa3bSJed Brown 
9340a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9350a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
9360a96aa3bSJed Brown             q->p.user_int       = cellFlags[count++];
9370a96aa3bSJed Brown           }
9380a96aa3bSJed Brown         }
9399566063dSJacob Faibussowitsch         PetscCall(PetscFree(cellFlags));
9400a96aa3bSJed Brown 
9410a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
942792fecdfSBarry Smith         if (adaptAny) PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_flag_any, pforest_init_determine));
943792fecdfSBarry Smith         else PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_flag_all, pforest_init_determine));
944792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 0, pforest_refine_flag, NULL));
9450a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
946792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
94748a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), apforest->forest, apforest->cLocalStart, pforest->forest, 0, &preCoarseToFine, &coarseToPreFine));
9480a96aa3bSJed Brown       }
9490a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
9500a96aa3bSJed Brown         p4est_tree_t     *atree     = &(((p4est_tree_t *)apforest->forest->trees->array)[t]);
9510a96aa3bSJed Brown         p4est_tree_t     *tree      = &(((p4est_tree_t *)pforest->forest->trees->array)[t]);
9520a96aa3bSJed Brown         PetscInt          anumQuads = (PetscInt)atree->quadrants.elem_count, i;
9530a96aa3bSJed Brown         PetscInt          numQuads  = (PetscInt)tree->quadrants.elem_count;
9540a96aa3bSJed Brown         p4est_quadrant_t *aquads    = (p4est_quadrant_t *)atree->quadrants.array;
9550a96aa3bSJed Brown         p4est_quadrant_t *quads     = (p4est_quadrant_t *)tree->quadrants.array;
9560a96aa3bSJed Brown 
9570a96aa3bSJed Brown         if (anumQuads != numQuads) {
9580a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
9590a96aa3bSJed Brown         } else {
9600a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9610a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
9620a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
9630a96aa3bSJed Brown 
9640a96aa3bSJed Brown             if (aq->level != q->level) {
9650a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
9660a96aa3bSJed Brown               break;
9670a96aa3bSJed Brown             }
9680a96aa3bSJed Brown           }
9690a96aa3bSJed Brown         }
970ad540459SPierre Jolivet         if (ctx.anyChange) break;
9710a96aa3bSJed Brown       }
9720a96aa3bSJed Brown     }
9730a96aa3bSJed Brown     {
9740a96aa3bSJed Brown       PetscInt numLabels, l;
9750a96aa3bSJed Brown 
9769566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(adaptFrom, &numLabels));
9770a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
9780a96aa3bSJed Brown         PetscBool   isDepth, isCellType, isGhost, isVTK;
9790a96aa3bSJed Brown         DMLabel     label, labelNew;
9800a96aa3bSJed Brown         PetscInt    defVal;
9810a96aa3bSJed Brown         const char *name;
9820a96aa3bSJed Brown 
9839566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(adaptFrom, l, &name));
9849566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(adaptFrom, l, &label));
9859566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "depth", &isDepth));
9860a96aa3bSJed Brown         if (isDepth) continue;
9879566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "celltype", &isCellType));
9880a96aa3bSJed Brown         if (isCellType) continue;
9899566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "ghost", &isGhost));
9900a96aa3bSJed Brown         if (isGhost) continue;
9919566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "vtk", &isVTK));
9920a96aa3bSJed Brown         if (isVTK) continue;
9939566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm, name));
9949566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm, name, &labelNew));
9959566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label, &defVal));
9969566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
9970a96aa3bSJed Brown       }
9980a96aa3bSJed Brown     }
9990a96aa3bSJed Brown   } else { /* initial */
10000a96aa3bSJed Brown     PetscInt initLevel, minLevel;
100166c0a4b5SToby Isaac   #if defined(PETSC_HAVE_MPIUNI)
100266c0a4b5SToby Isaac     sc_MPI_Comm comm = sc_MPI_COMM_WORLD;
100366c0a4b5SToby Isaac   #else
100466c0a4b5SToby Isaac     MPI_Comm comm = PetscObjectComm((PetscObject)dm);
100566c0a4b5SToby Isaac   #endif
10060a96aa3bSJed Brown 
10079566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm, &initLevel));
10089566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
10099371c9d4SSatish Balay     PetscCallP4estReturn(pforest->forest, p4est_new_ext,
10109371c9d4SSatish Balay                          (comm, pforest->topo->conn, 0, /* minimum number of quadrants per processor */
10110a96aa3bSJed Brown                           initLevel,                    /* level of refinement */
10120a96aa3bSJed Brown                           1,                            /* uniform refinement */
10130a96aa3bSJed Brown                           0,                            /* we don't allocate any per quadrant data */
10140a96aa3bSJed Brown                           NULL,                         /* there is no special quadrant initialization */
10150a96aa3bSJed Brown                           (void *)dm));                 /* this dm is the user context */
10160a96aa3bSJed Brown 
10170a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10180a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
10190a96aa3bSJed Brown       PetscBool   flgPattern, flgFractal;
10200a96aa3bSJed Brown       PetscInt    corner = 0;
10210a96aa3bSJed Brown       PetscInt    corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
10220a96aa3bSJed Brown       PetscReal   likelihood = 1. / P4EST_DIM;
10230a96aa3bSJed Brown       PetscInt    pattern;
10240a96aa3bSJed Brown       const char *prefix;
10250a96aa3bSJed Brown 
10269566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
10279566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEList(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_pattern", DMRefinePatternName, PATTERN_COUNT, &pattern, &flgPattern));
10289566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_corner", &corner, NULL));
10299566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_fractal_corners", corners, &ncorner, &flgFractal));
10309566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_hash_likelihood", &likelihood, NULL));
10310a96aa3bSJed Brown 
10320a96aa3bSJed Brown       if (flgPattern) {
10330a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
10340a96aa3bSJed Brown         PetscInt            maxLevel;
10350a96aa3bSJed Brown 
10369566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &maxLevel));
10374dfa11a4SJacob Faibussowitsch         PetscCall(PetscNew(&ctx));
10380a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel, P4EST_QMAXLEVEL);
10390a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10400a96aa3bSJed Brown         switch (pattern) {
10410a96aa3bSJed Brown         case PATTERN_HASH:
10420a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
10430a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
10440a96aa3bSJed Brown           break;
10450a96aa3bSJed Brown         case PATTERN_CORNER:
10460a96aa3bSJed Brown           ctx->corner    = corner;
10470a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
10480a96aa3bSJed Brown           break;
1049d71ae5a4SJacob Faibussowitsch         case PATTERN_CENTER:
1050d71ae5a4SJacob Faibussowitsch           ctx->refine_fn = DMRefinePattern_Center;
1051d71ae5a4SJacob Faibussowitsch           break;
10520a96aa3bSJed Brown         case PATTERN_FRACTAL:
10530a96aa3bSJed Brown           if (flgFractal) {
10540a96aa3bSJed Brown             PetscInt i;
10550a96aa3bSJed Brown 
10560a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
10570a96aa3bSJed Brown           } else {
10580a96aa3bSJed Brown   #if !defined(P4_TO_P8)
10590a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
10600a96aa3bSJed Brown   #else
10610a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
10620a96aa3bSJed Brown   #endif
10630a96aa3bSJed Brown           }
10640a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
10650a96aa3bSJed Brown           break;
1066d71ae5a4SJacob Faibussowitsch         default:
1067d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Not a valid refinement pattern");
10680a96aa3bSJed Brown         }
10690a96aa3bSJed Brown 
10700a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)ctx;
1071792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 1, ctx->refine_fn, NULL));
1072792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
10739566063dSJacob Faibussowitsch         PetscCall(PetscFree(ctx));
10740a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
10750a96aa3bSJed Brown       }
10760a96aa3bSJed Brown     }
10770a96aa3bSJed Brown   }
10780a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
10790a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
10800a96aa3bSJed Brown 
10819566063dSJacob Faibussowitsch     PetscCall(DMPforestGetRefinementLevel(dm, &currLevel));
10829566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm, &initLevel));
10839566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
10840a96aa3bSJed Brown     if (currLevel > minLevel) {
10850a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
10860a96aa3bSJed Brown       DMLabel            coarsen;
10870a96aa3bSJed Brown       DM                 coarseDM;
10880a96aa3bSJed Brown 
10899566063dSJacob Faibussowitsch       PetscCall(DMForestTemplate(dm, MPI_COMM_NULL, &coarseDM));
10909566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityPurpose(coarseDM, DM_ADAPT_COARSEN));
10919566063dSJacob Faibussowitsch       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
10929566063dSJacob Faibussowitsch       PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
10939566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityLabel(coarseDM, coarsen));
10949566063dSJacob Faibussowitsch       PetscCall(DMLabelDestroy(&coarsen));
10959566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm, coarseDM));
10969566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)coarseDM));
10970a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
10989566063dSJacob Faibussowitsch       PetscCall(DMForestSetInitialRefinement(coarseDM, initLevel));
10999566063dSJacob Faibussowitsch       PetscCall(DMForestSetMinimumRefinement(coarseDM, minLevel));
11000a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest *)((DM_Forest *)coarseDM->data)->data;
11010a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
11020a96aa3bSJed Brown     }
11030a96aa3bSJed Brown   }
11040a96aa3bSJed Brown 
11050a96aa3bSJed Brown   { /* repartitioning and overlap */
11060a96aa3bSJed Brown     PetscMPIInt size, rank;
11070a96aa3bSJed Brown 
11089566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
11099566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
11100a96aa3bSJed Brown     if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
11110a96aa3bSJed Brown       PetscBool      copyForest  = PETSC_FALSE;
11120a96aa3bSJed Brown       p4est_t       *forest_copy = NULL;
11130a96aa3bSJed Brown       p4est_gloidx_t shipped     = 0;
11140a96aa3bSJed Brown 
11150a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
1116792fecdfSBarry Smith       if (copyForest) PetscCallP4estReturn(forest_copy, p4est_copy, (pforest->forest, 0));
11170a96aa3bSJed Brown 
11180a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
1119792fecdfSBarry Smith         PetscCallP4estReturn(shipped, p4est_partition_ext, (pforest->forest, (int)pforest->partition_for_coarsening, NULL));
11200a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Non-uniform partition cases not implemented yet");
11210a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
11220a96aa3bSJed Brown       if (forest_copy) {
11230a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
11240a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
11250a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
11260a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
11270a96aa3bSJed Brown           PetscSFNode   *repartRoots;
11280a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
11290a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank + 1];
11300a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
11310a96aa3bSJed Brown 
11320a96aa3bSJed Brown           numRoots  = (PetscInt)(forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
11330a96aa3bSJed Brown           numLeaves = (PetscInt)(postEnd - postStart);
11349566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeOverlappingRanks(size, rank, pforest->forest, forest_copy, &pStart, &pEnd));
11359566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1((PetscInt)pforest->forest->local_num_quadrants, &repartRoots));
11360a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
11370a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
11380a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p + 1];
11390a96aa3bSJed Brown             PetscInt       q;
11400a96aa3bSJed Brown 
11410a96aa3bSJed Brown             if (preEnd == preStart) continue;
114208401ef6SPierre Jolivet             PetscCheck(preStart <= postStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad partition overlap computation");
11430a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
11440a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
11450a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
11460a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
11470a96aa3bSJed Brown             }
11480a96aa3bSJed Brown             partOffset = preEnd;
11490a96aa3bSJed Brown           }
11509566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &repartSF));
11519566063dSJacob Faibussowitsch           PetscCall(PetscSFSetGraph(repartSF, numRoots, numLeaves, NULL, PETSC_OWN_POINTER, repartRoots, PETSC_OWN_POINTER));
11529566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(repartSF));
11530a96aa3bSJed Brown           if (preCoarseToFine) {
11540a96aa3bSJed Brown             PetscSF         repartSFembed, preCoarseToFineNew;
11550a96aa3bSJed Brown             PetscInt        nleaves;
11560a96aa3bSJed Brown             const PetscInt *leaves;
11570a96aa3bSJed Brown 
11589566063dSJacob Faibussowitsch             PetscCall(PetscSFSetUp(preCoarseToFine));
11599566063dSJacob Faibussowitsch             PetscCall(PetscSFGetGraph(preCoarseToFine, NULL, &nleaves, &leaves, NULL));
11600a96aa3bSJed Brown             if (leaves) {
11619566063dSJacob Faibussowitsch               PetscCall(PetscSFCreateEmbeddedRootSF(repartSF, nleaves, leaves, &repartSFembed));
11620a96aa3bSJed Brown             } else {
11630a96aa3bSJed Brown               repartSFembed = repartSF;
11649566063dSJacob Faibussowitsch               PetscCall(PetscObjectReference((PetscObject)repartSFembed));
11650a96aa3bSJed Brown             }
11669566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(preCoarseToFine, repartSFembed, &preCoarseToFineNew));
11679566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&preCoarseToFine));
11689566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFembed));
11690a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
11700a96aa3bSJed Brown           }
11710a96aa3bSJed Brown           if (coarseToPreFine) {
11720a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
11730a96aa3bSJed Brown 
11749566063dSJacob Faibussowitsch             PetscCall(PetscSFCreateInverseSF(repartSF, &repartSFinv));
11759566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(repartSFinv, coarseToPreFine, &coarseToPreFineNew));
11769566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&coarseToPreFine));
11779566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFinv));
11780a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
11790a96aa3bSJed Brown           }
11809566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&repartSF));
11810a96aa3bSJed Brown         }
1182792fecdfSBarry Smith         PetscCallP4est(p4est_destroy, (forest_copy));
11830a96aa3bSJed Brown       }
11840a96aa3bSJed Brown     }
11850a96aa3bSJed Brown     if (size > 1) {
11860a96aa3bSJed Brown       PetscInt overlap;
11870a96aa3bSJed Brown 
11889566063dSJacob Faibussowitsch       PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
11890a96aa3bSJed Brown 
11900a96aa3bSJed Brown       if (adaptFrom) {
11910a96aa3bSJed Brown         PetscInt aoverlap;
11920a96aa3bSJed Brown 
11939566063dSJacob Faibussowitsch         PetscCall(DMForestGetPartitionOverlap(adaptFrom, &aoverlap));
1194ad540459SPierre Jolivet         if (aoverlap != overlap) ctx.anyChange = PETSC_TRUE;
11950a96aa3bSJed Brown       }
11960a96aa3bSJed Brown 
11970a96aa3bSJed Brown       if (overlap > 0) {
11980a96aa3bSJed Brown         PetscInt i, cLocalStart;
11990a96aa3bSJed Brown         PetscInt cEnd;
12000a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
12010a96aa3bSJed Brown 
1202792fecdfSBarry Smith         PetscCallP4estReturn(pforest->ghost, p4est_ghost_new, (pforest->forest, P4EST_CONNECT_FULL));
1203792fecdfSBarry Smith         PetscCallP4estReturn(pforest->lnodes, p4est_lnodes_new, (pforest->forest, pforest->ghost, -P4EST_DIM));
1204792fecdfSBarry Smith         PetscCallP4est(p4est_ghost_support_lnodes, (pforest->forest, pforest->lnodes, pforest->ghost));
1205792fecdfSBarry Smith         for (i = 1; i < overlap; i++) PetscCallP4est(p4est_ghost_expand_by_lnodes, (pforest->forest, pforest->lnodes, pforest->ghost));
12060a96aa3bSJed Brown 
12070a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
12080a96aa3bSJed Brown         cEnd                               = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
12090a96aa3bSJed Brown 
12100a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
12110a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
12129566063dSJacob Faibussowitsch           if (adaptFrom) PetscCall(DMForestGetCellSF(adaptFrom, &preCellSF));
12130a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
12149566063dSJacob Faibussowitsch           PetscCall(DMForestGetCellSF(dm, &cellSF));
12150a96aa3bSJed Brown         }
12160a96aa3bSJed Brown         if (preCoarseToFine) {
12170a96aa3bSJed Brown           PetscSF            preCoarseToFineNew;
12180a96aa3bSJed Brown           PetscInt           nleaves, nroots, *leavesNew, i, nleavesNew;
12190a96aa3bSJed Brown           const PetscInt    *leaves;
12200a96aa3bSJed Brown           const PetscSFNode *remotes;
12210a96aa3bSJed Brown           PetscSFNode       *remotesAll;
12220a96aa3bSJed Brown 
12239566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(preCoarseToFine));
12249566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCoarseToFine, &nroots, &nleaves, &leaves, &remotes));
12259566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(cEnd, &remotesAll));
12260a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
12270a96aa3bSJed Brown             remotesAll[i].rank  = -1;
12280a96aa3bSJed Brown             remotesAll[i].index = -1;
12290a96aa3bSJed Brown           }
12300a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
12319566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(cellSF));
12329566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(cellSF, MPIU_2INT, remotesAll, remotesAll, MPI_REPLACE));
12339566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(cellSF, MPIU_2INT, remotesAll, remotesAll, MPI_REPLACE));
12340a96aa3bSJed Brown           nleavesNew = 0;
12350a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12360a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
12370a96aa3bSJed Brown           }
12389566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesNew, &leavesNew));
12390a96aa3bSJed Brown           nleavesNew = 0;
12400a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12410a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
12420a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
12430a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
12440a96aa3bSJed Brown               nleavesNew++;
12450a96aa3bSJed Brown             }
12460a96aa3bSJed Brown           }
12479566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &preCoarseToFineNew));
12480a96aa3bSJed Brown           if (nleavesNew < cEnd) {
12499566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew, nroots, nleavesNew, leavesNew, PETSC_OWN_POINTER, remotesAll, PETSC_COPY_VALUES));
12500a96aa3bSJed Brown           } else { /* all cells are leaves */
12519566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
12529566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew, nroots, nleavesNew, NULL, PETSC_OWN_POINTER, remotesAll, PETSC_COPY_VALUES));
12530a96aa3bSJed Brown           }
12549566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesAll));
12559566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&preCoarseToFine));
12560a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12570a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12580a96aa3bSJed Brown         }
12590a96aa3bSJed Brown         if (coarseToPreFine) {
12600a96aa3bSJed Brown           PetscSF            coarseToPreFineNew;
12610a96aa3bSJed Brown           PetscInt           nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
12620a96aa3bSJed Brown           const PetscInt    *leaves;
12630a96aa3bSJed Brown           const PetscSFNode *remotes;
12640a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
12650a96aa3bSJed Brown 
12669566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(coarseToPreFine));
12679566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseToPreFine, &nroots, &nleaves, &leaves, &remotes));
12689566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCellSF, NULL, &nleavesCellSF, NULL, NULL));
12699566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nroots, &remotesNewRoot));
12709566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleaves, &remotesNew));
12710a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
12720a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
12730a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
12740a96aa3bSJed Brown           }
12759566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(coarseToPreFine, MPIU_2INT, remotesNewRoot, remotesNew, MPI_REPLACE));
12769566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(coarseToPreFine, MPIU_2INT, remotesNewRoot, remotesNew, MPI_REPLACE));
12779566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNewRoot));
12789566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesCellSF, &remotesExpanded));
12790a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12800a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
12810a96aa3bSJed Brown             remotesExpanded[i].index = -1;
12820a96aa3bSJed Brown           }
12830a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
12849566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNew));
12859566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(preCellSF, MPIU_2INT, remotesExpanded, remotesExpanded, MPI_REPLACE));
12869566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(preCellSF, MPIU_2INT, remotesExpanded, remotesExpanded, MPI_REPLACE));
12870a96aa3bSJed Brown 
12880a96aa3bSJed Brown           nleavesExpanded = 0;
12890a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12900a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
12910a96aa3bSJed Brown           }
12929566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesExpanded, &leavesNew));
12930a96aa3bSJed Brown           nleavesExpanded = 0;
12940a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12950a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
12960a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
12970a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
12980a96aa3bSJed Brown               nleavesExpanded++;
12990a96aa3bSJed Brown             }
13000a96aa3bSJed Brown           }
13019566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &coarseToPreFineNew));
13020a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
13039566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew, cEnd, nleavesExpanded, leavesNew, PETSC_OWN_POINTER, remotesExpanded, PETSC_COPY_VALUES));
13040a96aa3bSJed Brown           } else {
13059566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
13069566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew, cEnd, nleavesExpanded, NULL, PETSC_OWN_POINTER, remotesExpanded, PETSC_COPY_VALUES));
13070a96aa3bSJed Brown           }
13089566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesExpanded));
13099566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseToPreFine));
13100a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
13110a96aa3bSJed Brown         }
13120a96aa3bSJed Brown       }
13130a96aa3bSJed Brown     }
13140a96aa3bSJed Brown   }
13150a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
13160a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
13170a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
1318712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&ctx.anyChange, &(pforest->adaptivitySuccess), 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
13199566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, NULL));
13203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13210a96aa3bSJed Brown }
13220a96aa3bSJed Brown 
13230a96aa3bSJed Brown   #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
1324d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success)
1325d71ae5a4SJacob Faibussowitsch {
13260a96aa3bSJed Brown   DM_Forest         *forest;
13270a96aa3bSJed Brown   DM_Forest_pforest *pforest;
13280a96aa3bSJed Brown 
13290a96aa3bSJed Brown   PetscFunctionBegin;
13300a96aa3bSJed Brown   forest   = (DM_Forest *)dm->data;
13310a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *)forest->data;
13320a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
13333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13340a96aa3bSJed Brown }
13350a96aa3bSJed Brown 
13360a96aa3bSJed Brown   #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
1337d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer)
1338d71ae5a4SJacob Faibussowitsch {
13390a96aa3bSJed Brown   DM dm = (DM)odm;
13400a96aa3bSJed Brown 
13410a96aa3bSJed Brown   PetscFunctionBegin;
13420a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13430a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13449566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13450a96aa3bSJed Brown   switch (viewer->format) {
13460a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
13479371c9d4SSatish Balay   case PETSC_VIEWER_ASCII_INFO: {
13480a96aa3bSJed Brown     PetscInt    dim;
13490a96aa3bSJed Brown     const char *name;
13500a96aa3bSJed Brown 
13519566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
13529566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
135363a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "Forest %s in %" PetscInt_FMT " dimensions:\n", name, dim));
135463a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Forest in %" PetscInt_FMT " dimensions:\n", dim));
1355f4d061e9SPierre Jolivet   } /* fall through */
13560a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
13579371c9d4SSatish Balay   case PETSC_VIEWER_LOAD_BALANCE: {
13580a96aa3bSJed Brown     DM plex;
13590a96aa3bSJed Brown 
13609566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dm, &plex));
13619566063dSJacob Faibussowitsch     PetscCall(DMView(plex, viewer));
13629371c9d4SSatish Balay   } break;
1363d71ae5a4SJacob Faibussowitsch   default:
1364d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13650a96aa3bSJed Brown   }
13663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13670a96aa3bSJed Brown }
13680a96aa3bSJed Brown 
13690a96aa3bSJed Brown   #define DMView_VTK_pforest _append_pforest(DMView_VTK)
1370d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer)
1371d71ae5a4SJacob Faibussowitsch {
13720a96aa3bSJed Brown   DM                 dm      = (DM)odm;
13730a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
13740a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
13750a96aa3bSJed Brown   PetscBool          isvtk;
13760a96aa3bSJed Brown   PetscReal          vtkScale = 1. - PETSC_MACHINE_EPSILON;
13770a96aa3bSJed Brown   PetscViewer_VTK   *vtk      = (PetscViewer_VTK *)viewer->data;
13780a96aa3bSJed Brown   const char        *name;
13790a96aa3bSJed Brown   char              *filenameStrip = NULL;
13800a96aa3bSJed Brown   PetscBool          hasExt;
13810a96aa3bSJed Brown   size_t             len;
13820a96aa3bSJed Brown   p4est_geometry_t  *geom;
13830a96aa3bSJed Brown 
13840a96aa3bSJed Brown   PetscFunctionBegin;
13850a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13860a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13879566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13880a96aa3bSJed Brown   geom = pforest->topo->geom;
13899566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
139028b400f6SJacob Faibussowitsch   PetscCheck(isvtk, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
13910a96aa3bSJed Brown   switch (viewer->format) {
13920a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
139328b400f6SJacob Faibussowitsch     PetscCheck(pforest->forest, PetscObjectComm(odm), PETSC_ERR_ARG_WRONG, "DM has not been setup with a valid forest");
13940a96aa3bSJed Brown     name = vtk->filename;
13959566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(name, &len));
13969566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(name + len - 4, ".vtu", &hasExt));
13970a96aa3bSJed Brown     if (hasExt) {
13989566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(name, &filenameStrip));
13990a96aa3bSJed Brown       filenameStrip[len - 4] = '\0';
14000a96aa3bSJed Brown       name                   = filenameStrip;
14010a96aa3bSJed Brown     }
1402792fecdfSBarry Smith     if (!pforest->topo->geom) PetscCallP4estReturn(geom, p4est_geometry_new_connectivity, (pforest->topo->conn));
14030a96aa3bSJed Brown     {
14040a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
14050a96aa3bSJed Brown       int                  footerr;
14060a96aa3bSJed Brown 
1407792fecdfSBarry Smith       PetscCallP4estReturn(pvtk, p4est_vtk_context_new, (pforest->forest, name));
1408792fecdfSBarry Smith       PetscCallP4est(p4est_vtk_context_set_geom, (pvtk, geom));
1409792fecdfSBarry Smith       PetscCallP4est(p4est_vtk_context_set_scale, (pvtk, (double)vtkScale));
1410792fecdfSBarry Smith       PetscCallP4estReturn(pvtk, p4est_vtk_write_header, (pvtk));
141128b400f6SJacob Faibussowitsch       PetscCheck(pvtk, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_header() failed");
14129371c9d4SSatish Balay       PetscCallP4estReturn(pvtk, p4est_vtk_write_cell_dataf,
14139371c9d4SSatish Balay                            (pvtk, 1, /* write tree */
14140a96aa3bSJed Brown                             1,       /* write level */
14150a96aa3bSJed Brown                             1,       /* write rank */
14160a96aa3bSJed Brown                             0,       /* do not wrap rank */
14170a96aa3bSJed Brown                             0,       /* no scalar fields */
14180a96aa3bSJed Brown                             0,       /* no vector fields */
14190a96aa3bSJed Brown                             pvtk));
142028b400f6SJacob Faibussowitsch       PetscCheck(pvtk, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_cell_dataf() failed");
1421792fecdfSBarry Smith       PetscCallP4estReturn(footerr, p4est_vtk_write_footer, (pvtk));
142228b400f6SJacob Faibussowitsch       PetscCheck(!footerr, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_footer() failed");
14230a96aa3bSJed Brown     }
1424792fecdfSBarry Smith     if (!pforest->topo->geom) PetscCallP4est(p4est_geometry_destroy, (geom));
14259566063dSJacob Faibussowitsch     PetscCall(PetscFree(filenameStrip));
14260a96aa3bSJed Brown     break;
1427d71ae5a4SJacob Faibussowitsch   default:
1428d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
14290a96aa3bSJed Brown   }
14303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14310a96aa3bSJed Brown }
14320a96aa3bSJed Brown 
14330a96aa3bSJed Brown   #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
1434d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer)
1435d71ae5a4SJacob Faibussowitsch {
14360a96aa3bSJed Brown   DM plex;
14370a96aa3bSJed Brown 
14380a96aa3bSJed Brown   PetscFunctionBegin;
14399566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14409566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14419566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14430a96aa3bSJed Brown }
14440a96aa3bSJed Brown 
14450a96aa3bSJed Brown   #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
1446d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer)
1447d71ae5a4SJacob Faibussowitsch {
14480a96aa3bSJed Brown   DM plex;
14490a96aa3bSJed Brown 
14500a96aa3bSJed Brown   PetscFunctionBegin;
14519566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14529566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14539566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14550a96aa3bSJed Brown }
14560a96aa3bSJed Brown 
14570a96aa3bSJed Brown   #define DMView_pforest _append_pforest(DMView)
1458d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer)
1459d71ae5a4SJacob Faibussowitsch {
14600a96aa3bSJed Brown   PetscBool isascii, isvtk, ishdf5, isglvis;
14610a96aa3bSJed Brown 
14620a96aa3bSJed Brown   PetscFunctionBegin;
14630a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14640a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
14659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
14669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
14679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
14689566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
14690a96aa3bSJed Brown   if (isascii) {
14709566063dSJacob Faibussowitsch     PetscCall(DMView_ASCII_pforest((PetscObject)dm, viewer));
14710a96aa3bSJed Brown   } else if (isvtk) {
14729566063dSJacob Faibussowitsch     PetscCall(DMView_VTK_pforest((PetscObject)dm, viewer));
14730a96aa3bSJed Brown   } else if (ishdf5) {
14749566063dSJacob Faibussowitsch     PetscCall(DMView_HDF5_pforest(dm, viewer));
14750a96aa3bSJed Brown   } else if (isglvis) {
14769566063dSJacob Faibussowitsch     PetscCall(DMView_GLVis_pforest(dm, viewer));
14770a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer not supported (not VTK, HDF5, or GLVis)");
14783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14790a96aa3bSJed Brown }
14800a96aa3bSJed Brown 
1481d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq)
1482d71ae5a4SJacob Faibussowitsch {
14830a96aa3bSJed Brown   PetscInt *ttf, f, t, g, count;
14840a96aa3bSJed Brown   PetscInt  numFacets;
14850a96aa3bSJed Brown 
14860a96aa3bSJed Brown   PetscFunctionBegin;
14870a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
14889566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFacets, &ttf));
14890a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
14900a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
14910a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
14920a96aa3bSJed Brown       if (ttf[g] == -1) {
14930a96aa3bSJed Brown         PetscInt ng;
14940a96aa3bSJed Brown 
14950a96aa3bSJed Brown         ttf[g]  = count++;
14960a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
14970a96aa3bSJed Brown         ttf[ng] = ttf[g];
14980a96aa3bSJed Brown       }
14990a96aa3bSJed Brown     }
15000a96aa3bSJed Brown   }
15010a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
15023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15030a96aa3bSJed Brown }
15040a96aa3bSJed Brown 
1505d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq)
1506d71ae5a4SJacob Faibussowitsch {
15070a96aa3bSJed Brown   p4est_topidx_t numTrees, numVerts, numCorns, numCtt;
15080a96aa3bSJed Brown   PetscSection   ctt;
15090a96aa3bSJed Brown   #if defined(P4_TO_P8)
15100a96aa3bSJed Brown   p4est_topidx_t numEdges, numEtt;
15110a96aa3bSJed Brown   PetscSection   ett;
15120a96aa3bSJed Brown   PetscInt       eStart, eEnd, e, ettSize;
15130a96aa3bSJed Brown   PetscInt       vertOff = 1 + P4EST_FACES + P8EST_EDGES;
15140a96aa3bSJed Brown   PetscInt       edgeOff = 1 + P4EST_FACES;
15150a96aa3bSJed Brown   #else
15160a96aa3bSJed Brown   PetscInt vertOff = 1 + P4EST_FACES;
15170a96aa3bSJed Brown   #endif
15180a96aa3bSJed Brown   p4est_connectivity_t *conn;
15190a96aa3bSJed Brown   PetscInt              cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
15200a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
15210a96aa3bSJed Brown   PetscInt             *ttf;
15220a96aa3bSJed Brown 
15230a96aa3bSJed Brown   PetscFunctionBegin;
15240a96aa3bSJed Brown   /* 1: count objects, allocate */
15259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
15269566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cEnd - cStart, &numTrees));
15270a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
15289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
15299566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(vEnd - vStart, &numCorns));
15309566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &ctt));
15319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ctt, vStart, vEnd));
15320a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
15330a96aa3bSJed Brown     PetscInt s;
15340a96aa3bSJed Brown 
15359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
15360a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15370a96aa3bSJed Brown       PetscInt p = star[2 * s];
15380a96aa3bSJed Brown 
15390a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15400a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
15410a96aa3bSJed Brown          * only protects against periodicity problems */
15429566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
154363a3b9bcSJacob 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);
15440a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
15450a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
15460a96aa3bSJed Brown 
15471dca8a05SBarry Smith           PetscCheck(cellVert >= vStart && cellVert < vEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure: vertices");
154848a46eb9SPierre Jolivet           if (cellVert == v) PetscCall(PetscSectionAddDof(ctt, v, 1));
15490a96aa3bSJed Brown         }
15509566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
15510a96aa3bSJed Brown       }
15520a96aa3bSJed Brown     }
15539566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
15540a96aa3bSJed Brown   }
15559566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ctt));
15569566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ctt, &cttSize));
15579566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cttSize, &numCtt));
15580a96aa3bSJed Brown   #if defined(P4_TO_P8)
15599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, P4EST_DIM - 1, &eStart, &eEnd));
15609566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(eEnd - eStart, &numEdges));
15619566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &ett));
15629566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ett, eStart, eEnd));
15630a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
15640a96aa3bSJed Brown     PetscInt s;
15650a96aa3bSJed Brown 
15669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
15670a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15680a96aa3bSJed Brown       PetscInt p = star[2 * s];
15690a96aa3bSJed Brown 
15700a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15710a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
15720a96aa3bSJed Brown          * only protects against periodicity problems */
15739566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
157408401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cell with wrong closure size");
15750a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
15760a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
15770a96aa3bSJed Brown 
15781dca8a05SBarry Smith           PetscCheck(cellEdge >= eStart && cellEdge < eEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure: edges");
157948a46eb9SPierre Jolivet           if (cellEdge == e) PetscCall(PetscSectionAddDof(ett, e, 1));
15800a96aa3bSJed Brown         }
15819566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
15820a96aa3bSJed Brown       }
15830a96aa3bSJed Brown     }
15849566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
15850a96aa3bSJed Brown   }
15869566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ett));
15879566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ett, &ettSize));
15889566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(ettSize, &numEtt));
15890a96aa3bSJed Brown 
15900a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
1591792fecdfSBarry Smith   PetscCallP4estReturn(conn, p8est_connectivity_new, (numVerts, numTrees, numEdges, numEtt, numCorns, numCtt));
15920a96aa3bSJed Brown   #else
1593792fecdfSBarry Smith   PetscCallP4estReturn(conn, p4est_connectivity_new, (numVerts, numTrees, numCorns, numCtt));
15940a96aa3bSJed Brown   #endif
15950a96aa3bSJed Brown 
15960a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
15979566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 1, &fStart, &fEnd));
15989566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((cEnd - cStart) * P4EST_FACES, &ttf));
15990a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
16000a96aa3bSJed Brown     PetscInt        numSupp, s;
16010a96aa3bSJed Brown     PetscInt        myFace[2] = {-1, -1};
16020a96aa3bSJed Brown     PetscInt        myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
16030a96aa3bSJed Brown     const PetscInt *supp;
16040a96aa3bSJed Brown 
16059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numSupp));
16061dca8a05SBarry 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);
16079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &supp));
16080a96aa3bSJed Brown 
16090a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16100a96aa3bSJed Brown       PetscInt p = supp[s];
16110a96aa3bSJed Brown 
16120a96aa3bSJed Brown       if (p >= cEnd) {
16130a96aa3bSJed Brown         numSupp--;
16140a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
16150a96aa3bSJed Brown         break;
16160a96aa3bSJed Brown       }
16170a96aa3bSJed Brown     }
16180a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16190a96aa3bSJed Brown       PetscInt        p = supp[s], i;
16200a96aa3bSJed Brown       PetscInt        numCone;
16210a96aa3bSJed Brown       DMPolytopeType  ct;
16220a96aa3bSJed Brown       const PetscInt *cone;
16230a96aa3bSJed Brown       const PetscInt *ornt;
16240a96aa3bSJed Brown       PetscInt        orient = PETSC_MIN_INT;
16250a96aa3bSJed Brown 
16269566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &numCone));
162763a3b9bcSJacob 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);
16289566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
16299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[0], &ct));
16309566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
16310a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
16320a96aa3bSJed Brown         if (cone[i] == f) {
16330a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
16340a96aa3bSJed Brown           break;
16350a96aa3bSJed Brown         }
16360a96aa3bSJed Brown       }
163763a3b9bcSJacob Faibussowitsch       PetscCheck(i < P4EST_FACES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "cell %" PetscInt_FMT " faced %" PetscInt_FMT " mismatch", p, f);
16380a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
16390a96aa3bSJed Brown         DMPolytopeType ct;
16409566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
164163a3b9bcSJacob 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);
16420a96aa3bSJed Brown       }
16430a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
16440a96aa3bSJed Brown       if (numSupp == 1) {
16450a96aa3bSJed Brown         /* boundary faces indicated by self reference */
16460a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
16470a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t)PetscFaceToP4estFace[i];
16480a96aa3bSJed Brown       } else {
16490a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16500a96aa3bSJed Brown 
16510a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
16520a96aa3bSJed Brown         myFace[s]                                                                = PetscFaceToP4estFace[i];
16530a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
16540a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
16550a96aa3bSJed Brown         myOrnt[s] = DihedralCompose(N, orient, DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
16560a96aa3bSJed Brown       }
16570a96aa3bSJed Brown     }
16580a96aa3bSJed Brown     if (numSupp == 2) {
16590a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
16600a96aa3bSJed Brown         PetscInt       p = supp[s];
16610a96aa3bSJed Brown         PetscInt       orntAtoB;
16620a96aa3bSJed Brown         PetscInt       p4estOrient;
16630a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16640a96aa3bSJed Brown 
16650a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
16660a96aa3bSJed Brown          * permutation of this cell-facet's cone */
16670a96aa3bSJed Brown         orntAtoB = DihedralCompose(N, DihedralInvert(N, myOrnt[1 - s]), myOrnt[s]);
16680a96aa3bSJed Brown 
16690a96aa3bSJed Brown           /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
16700a96aa3bSJed Brown          * vertices around facet) */
16710a96aa3bSJed Brown   #if !defined(P4_TO_P8)
16720a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
16730a96aa3bSJed Brown   #else
16740a96aa3bSJed Brown         {
16750a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
16760a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
16770a96aa3bSJed Brown 
16780a96aa3bSJed Brown           /* swap bits */
16790a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
16800a96aa3bSJed Brown         }
16810a96aa3bSJed Brown   #endif
16820a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
16830a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
16840a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t)myFace[1 - s] + p4estOrient * P4EST_FACES;
16850a96aa3bSJed Brown       }
16860a96aa3bSJed Brown     }
16870a96aa3bSJed Brown   }
16880a96aa3bSJed Brown 
16890a96aa3bSJed Brown   #if defined(P4_TO_P8)
16900a96aa3bSJed Brown   /* 3: visit every edge */
16910a96aa3bSJed Brown   conn->ett_offset[0] = 0;
16920a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
16930a96aa3bSJed Brown     PetscInt off, s;
16940a96aa3bSJed Brown 
16959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ett, e, &off));
16960a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t)off;
16979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
16980a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
16990a96aa3bSJed Brown       PetscInt p = star[2 * s];
17000a96aa3bSJed Brown 
17010a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17029566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
170308401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure");
17040a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
17050a96aa3bSJed Brown           PetscInt       cellEdge = closure[2 * (c + edgeOff)];
17060a96aa3bSJed Brown           PetscInt       cellOrnt = closure[2 * (c + edgeOff) + 1];
17070a96aa3bSJed Brown           DMPolytopeType ct;
17080a96aa3bSJed Brown 
17099566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cellEdge, &ct));
17100a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
17110a96aa3bSJed Brown           if (cellEdge == e) {
17120a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
17130a96aa3bSJed Brown             PetscInt totalOrient;
17140a96aa3bSJed Brown 
17150a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
17160a96aa3bSJed Brown             totalOrient = DihedralCompose(2, cellOrnt, DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
17170a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
17180a96aa3bSJed Brown             totalOrient             = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
17190a96aa3bSJed Brown             conn->edge_to_tree[off] = (p4est_locidx_t)(p - cStart);
1720d5b43468SJose E. Roman             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standard (see
17210a96aa3bSJed Brown              * p8est_connectivity.h) */
17220a96aa3bSJed Brown             conn->edge_to_edge[off++]                                  = (int8_t)p4estEdge + P8EST_EDGES * totalOrient;
17230a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
17240a96aa3bSJed Brown           }
17250a96aa3bSJed Brown         }
17269566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
17270a96aa3bSJed Brown       }
17280a96aa3bSJed Brown     }
17299566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
17300a96aa3bSJed Brown   }
17319566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ett));
17320a96aa3bSJed Brown   #endif
17330a96aa3bSJed Brown 
17340a96aa3bSJed Brown   /* 4: visit every vertex */
17350a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
17360a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
17370a96aa3bSJed Brown     PetscInt off, s;
17380a96aa3bSJed Brown 
17399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ctt, v, &off));
17400a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t)off;
17419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
17420a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17430a96aa3bSJed Brown       PetscInt p = star[2 * s];
17440a96aa3bSJed Brown 
17450a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17469566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
174708401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure");
17480a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
17490a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
17500a96aa3bSJed Brown 
17510a96aa3bSJed Brown           if (cellVert == v) {
17520a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
17530a96aa3bSJed Brown 
17540a96aa3bSJed Brown             conn->corner_to_tree[off]                                       = (p4est_locidx_t)(p - cStart);
17550a96aa3bSJed Brown             conn->corner_to_corner[off++]                                   = (int8_t)p4estVert;
17560a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
17570a96aa3bSJed Brown           }
17580a96aa3bSJed Brown         }
17599566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
17600a96aa3bSJed Brown       }
17610a96aa3bSJed Brown     }
17629566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
17630a96aa3bSJed Brown   }
17649566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ctt));
17650a96aa3bSJed Brown 
17660a96aa3bSJed Brown   /* 5: Compute the coordinates */
17670a96aa3bSJed Brown   {
17680a96aa3bSJed Brown     PetscInt coordDim;
17690a96aa3bSJed Brown 
17709566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
17716858538eSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocalSetUp(dm));
17720a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
17730a96aa3bSJed Brown       PetscInt           dof;
17746858538eSMatthew G. Knepley       PetscBool          isDG;
17750a96aa3bSJed Brown       PetscScalar       *cellCoords = NULL;
17766858538eSMatthew G. Knepley       const PetscScalar *array;
17770a96aa3bSJed Brown 
17786858538eSMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17796858538eSMatthew 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);
17800a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
17810a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
17820a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
17830a96aa3bSJed Brown 
17840a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
17850a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
17860a96aa3bSJed Brown         for (i = 0; i < 3; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
17870a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
17880a96aa3bSJed Brown       }
17896858538eSMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17900a96aa3bSJed Brown     }
17910a96aa3bSJed Brown   }
17920a96aa3bSJed Brown 
17930a96aa3bSJed Brown   #if defined(P4EST_ENABLE_DEBUG)
179408401ef6SPierre Jolivet   PetscCheck(p4est_connectivity_is_valid(conn), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Plex to p4est conversion failed");
17950a96aa3bSJed Brown   #endif
17960a96aa3bSJed Brown 
17970a96aa3bSJed Brown   *connOut = conn;
17980a96aa3bSJed Brown 
17990a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
18000a96aa3bSJed Brown 
18013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18020a96aa3bSJed Brown }
18030a96aa3bSJed Brown 
1804d71ae5a4SJacob Faibussowitsch static PetscErrorCode locidx_to_PetscInt(sc_array_t *array)
1805d71ae5a4SJacob Faibussowitsch {
18060a96aa3bSJed Brown   sc_array_t *newarray;
18070a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18080a96aa3bSJed Brown 
18090a96aa3bSJed Brown   PetscFunctionBegin;
181008401ef6SPierre Jolivet   PetscCheck(array->elem_size == sizeof(p4est_locidx_t), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong locidx size");
18110a96aa3bSJed Brown 
18123ba16761SJacob Faibussowitsch   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(PETSC_SUCCESS);
18130a96aa3bSJed Brown 
18140a96aa3bSJed Brown   newarray = sc_array_new_size(sizeof(PetscInt), array->elem_count);
18150a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18160a96aa3bSJed Brown     p4est_locidx_t il = *((p4est_locidx_t *)sc_array_index(array, zz));
18170a96aa3bSJed Brown     PetscInt      *ip = (PetscInt *)sc_array_index(newarray, zz);
18180a96aa3bSJed Brown 
18190a96aa3bSJed Brown     *ip = (PetscInt)il;
18200a96aa3bSJed Brown   }
18210a96aa3bSJed Brown 
18220a96aa3bSJed Brown   sc_array_reset(array);
18230a96aa3bSJed Brown   sc_array_init_size(array, sizeof(PetscInt), count);
18240a96aa3bSJed Brown   sc_array_copy(array, newarray);
18250a96aa3bSJed Brown   sc_array_destroy(newarray);
18263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18270a96aa3bSJed Brown }
18280a96aa3bSJed Brown 
1829d71ae5a4SJacob Faibussowitsch static PetscErrorCode coords_double_to_PetscScalar(sc_array_t *array, PetscInt dim)
1830d71ae5a4SJacob Faibussowitsch {
18310a96aa3bSJed Brown   sc_array_t *newarray;
18320a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18330a96aa3bSJed Brown 
18340a96aa3bSJed Brown   PetscFunctionBegin;
18351dca8a05SBarry Smith   PetscCheck(array->elem_size == 3 * sizeof(double), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong coordinate size");
18360a96aa3bSJed Brown   #if !defined(PETSC_USE_COMPLEX)
18373ba16761SJacob Faibussowitsch   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(PETSC_SUCCESS);
18380a96aa3bSJed Brown   #endif
18390a96aa3bSJed Brown 
18400a96aa3bSJed Brown   newarray = sc_array_new_size(dim * sizeof(PetscScalar), array->elem_count);
18410a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18420a96aa3bSJed Brown     int          i;
18430a96aa3bSJed Brown     double      *id = (double *)sc_array_index(array, zz);
18440a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar *)sc_array_index(newarray, zz);
18450a96aa3bSJed Brown 
18460a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
18470a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim, 3); i++) ip[i] = (PetscScalar)id[i];
18480a96aa3bSJed Brown   }
18490a96aa3bSJed Brown 
18500a96aa3bSJed Brown   sc_array_reset(array);
18510a96aa3bSJed Brown   sc_array_init_size(array, dim * sizeof(PetscScalar), count);
18520a96aa3bSJed Brown   sc_array_copy(array, newarray);
18530a96aa3bSJed Brown   sc_array_destroy(newarray);
18543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18550a96aa3bSJed Brown }
18560a96aa3bSJed Brown 
1857d71ae5a4SJacob Faibussowitsch static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t *array)
1858d71ae5a4SJacob Faibussowitsch {
18590a96aa3bSJed Brown   sc_array_t *newarray;
18600a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18610a96aa3bSJed Brown 
18620a96aa3bSJed Brown   PetscFunctionBegin;
18631dca8a05SBarry Smith   PetscCheck(array->elem_size == 2 * sizeof(p4est_locidx_t), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong locidx size");
18640a96aa3bSJed Brown 
18650a96aa3bSJed Brown   newarray = sc_array_new_size(sizeof(PetscSFNode), array->elem_count);
18660a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18670a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t *)sc_array_index(array, zz);
18680a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode *)sc_array_index(newarray, zz);
18690a96aa3bSJed Brown 
18700a96aa3bSJed Brown     ip->rank  = (PetscInt)il[0];
18710a96aa3bSJed Brown     ip->index = (PetscInt)il[1];
18720a96aa3bSJed Brown   }
18730a96aa3bSJed Brown 
18740a96aa3bSJed Brown   sc_array_reset(array);
18750a96aa3bSJed Brown   sc_array_init_size(array, sizeof(PetscSFNode), count);
18760a96aa3bSJed Brown   sc_array_copy(array, newarray);
18770a96aa3bSJed Brown   sc_array_destroy(newarray);
18783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18790a96aa3bSJed Brown }
18800a96aa3bSJed Brown 
1881d71ae5a4SJacob Faibussowitsch static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM *plex)
1882d71ae5a4SJacob Faibussowitsch {
18830a96aa3bSJed Brown   PetscFunctionBegin;
18840a96aa3bSJed Brown   {
18850a96aa3bSJed Brown     sc_array_t    *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
18860a96aa3bSJed Brown     sc_array_t    *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
18870a96aa3bSJed Brown     sc_array_t    *cones             = sc_array_new(sizeof(p4est_locidx_t));
18880a96aa3bSJed Brown     sc_array_t    *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
18890a96aa3bSJed Brown     sc_array_t    *coords            = sc_array_new(3 * sizeof(double));
18900a96aa3bSJed Brown     sc_array_t    *children          = sc_array_new(sizeof(p4est_locidx_t));
18910a96aa3bSJed Brown     sc_array_t    *parents           = sc_array_new(sizeof(p4est_locidx_t));
18920a96aa3bSJed Brown     sc_array_t    *childids          = sc_array_new(sizeof(p4est_locidx_t));
18930a96aa3bSJed Brown     sc_array_t    *leaves            = sc_array_new(sizeof(p4est_locidx_t));
18940a96aa3bSJed Brown     sc_array_t    *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
18950a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
18960a96aa3bSJed Brown 
1897792fecdfSBarry 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));
18980a96aa3bSJed Brown 
18999566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
19009566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
19019566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
19029566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
19039566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, P4EST_DIM));
19040a96aa3bSJed Brown 
19059566063dSJacob Faibussowitsch     PetscCall(DMPlexCreate(PETSC_COMM_SELF, plex));
19069566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(*plex, P4EST_DIM));
19079566063dSJacob 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));
19089566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(*plex));
19090a96aa3bSJed Brown     sc_array_destroy(points_per_dim);
19100a96aa3bSJed Brown     sc_array_destroy(cone_sizes);
19110a96aa3bSJed Brown     sc_array_destroy(cones);
19120a96aa3bSJed Brown     sc_array_destroy(cone_orientations);
19130a96aa3bSJed Brown     sc_array_destroy(coords);
19140a96aa3bSJed Brown     sc_array_destroy(children);
19150a96aa3bSJed Brown     sc_array_destroy(parents);
19160a96aa3bSJed Brown     sc_array_destroy(childids);
19170a96aa3bSJed Brown     sc_array_destroy(leaves);
19180a96aa3bSJed Brown     sc_array_destroy(remotes);
19190a96aa3bSJed Brown   }
19203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19210a96aa3bSJed Brown }
19220a96aa3bSJed Brown 
19230a96aa3bSJed Brown   #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
1924d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
1925d71ae5a4SJacob Faibussowitsch {
19260a96aa3bSJed Brown   PetscInt coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
19270a96aa3bSJed Brown 
19280a96aa3bSJed Brown   PetscFunctionBegin;
19290a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
19300a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
19310a96aa3bSJed Brown     if (childB) *childB = childA;
19323ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19330a96aa3bSJed Brown   }
19349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
19356aad120cSJose E. Roman   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invariant under rotation */
19360a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
19370a96aa3bSJed Brown     if (childB) *childB = childA;
19383ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19390a96aa3bSJed Brown   }
19400a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
19419566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
19420a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
19430a96aa3bSJed Brown   }
194463a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
194528b400f6SJacob Faibussowitsch   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
19460a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
19470a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
19480a96aa3bSJed Brown     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
19490a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
19500a96aa3bSJed Brown 
19519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
19529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, childA, &supp));
19530a96aa3bSJed Brown 
19540a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
19550a96aa3bSJed Brown     for (i = 0; i < size; i++) {
19560a96aa3bSJed Brown       PetscInt sParent;
19570a96aa3bSJed Brown 
19580a96aa3bSJed Brown       sA = supp[i];
19590a96aa3bSJed Brown       if (sA == parent) continue;
19609566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
19610a96aa3bSJed Brown       if (sParent == parent) break;
19620a96aa3bSJed Brown     }
196308401ef6SPierre Jolivet     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
19640a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
19650a96aa3bSJed Brown      * parentOrientB */
19669566063dSJacob Faibussowitsch     PetscCall(DMReferenceTreeGetChildSymmetry_pforest(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
19679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
19689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sA, &coneA));
19699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sB, &coneB));
19709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
19719566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
19720a96aa3bSJed Brown     /* step through the cone of sA in natural order */
19730a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
19740a96aa3bSJed Brown       if (coneA[i] == childA) {
19750a96aa3bSJed Brown         /* if childA is at position i in coneA,
19760a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
19770a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
19780a96aa3bSJed Brown         if (childB) *childB = coneB[j];
19790a96aa3bSJed Brown         if (childOrientB) {
19800a96aa3bSJed Brown           DMPolytopeType ct;
19810a96aa3bSJed Brown           PetscInt       oBtrue;
19820a96aa3bSJed Brown 
19839566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
19840a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
19851dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
19860a96aa3bSJed Brown           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
19870a96aa3bSJed Brown           /* we may have to flip an edge */
19880a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
19890a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
19900a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
19910a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
19920a96aa3bSJed Brown         }
19930a96aa3bSJed Brown         break;
19940a96aa3bSJed Brown       }
19950a96aa3bSJed Brown     }
199608401ef6SPierre Jolivet     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
19973ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19980a96aa3bSJed Brown   }
19990a96aa3bSJed Brown   /* get the cone size and symmetry swap */
20009566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
20010a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
20020a96aa3bSJed Brown   if (dim == 2) {
20030a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
20040a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
20050a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
20060a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
20070a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
20080a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
20090a96aa3bSJed Brown   } else {
20100a96aa3bSJed Brown     oAvert     = parentOrientA;
20110a96aa3bSJed Brown     oBvert     = parentOrientB;
20120a96aa3bSJed Brown     ABswapVert = ABswap;
20130a96aa3bSJed Brown   }
20140a96aa3bSJed Brown   if (childB) {
20150a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
20160a96aa3bSJed Brown     PetscInt        p, posA = -1, numChildren, i;
20170a96aa3bSJed Brown     const PetscInt *children;
20180a96aa3bSJed Brown 
20190a96aa3bSJed Brown     /* count which position the child is in */
20209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
20210a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
20220a96aa3bSJed Brown       p = children[i];
20230a96aa3bSJed Brown       if (p == childA) {
20240a96aa3bSJed Brown         if (dim == 1) {
20250a96aa3bSJed Brown           posA = i;
20260a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
20270a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
20280a96aa3bSJed Brown         }
20290a96aa3bSJed Brown         break;
20300a96aa3bSJed Brown       }
20310a96aa3bSJed Brown     }
20320a96aa3bSJed Brown     if (posA >= coneSize) {
20330a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find childA in children of parent");
20340a96aa3bSJed Brown     } else {
20350a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
20360a96aa3bSJed Brown       PetscInt posB, childIdB;
20370a96aa3bSJed Brown 
20380a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
20390a96aa3bSJed Brown       if (dim == 1) {
20400a96aa3bSJed Brown         childIdB = posB;
20410a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
20420a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
20430a96aa3bSJed Brown       }
20440a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
20450a96aa3bSJed Brown     }
20460a96aa3bSJed Brown   }
20470a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
20483ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20490a96aa3bSJed Brown }
20500a96aa3bSJed Brown 
20510a96aa3bSJed Brown   #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
2052d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm)
2053d71ae5a4SJacob Faibussowitsch {
20540a96aa3bSJed Brown   p4est_connectivity_t *refcube;
20550a96aa3bSJed Brown   p4est_t              *root, *refined;
20560a96aa3bSJed Brown   DM                    dmRoot, dmRefined;
20570a96aa3bSJed Brown   DM_Plex              *mesh;
20580a96aa3bSJed Brown   PetscMPIInt           rank;
205966c0a4b5SToby Isaac   #if defined(PETSC_HAVE_MPIUNI)
206066c0a4b5SToby Isaac   sc_MPI_Comm comm_self = sc_MPI_COMM_SELF;
206166c0a4b5SToby Isaac   #else
206266c0a4b5SToby Isaac   MPI_Comm comm_self = PETSC_COMM_SELF;
206366c0a4b5SToby Isaac   #endif
20640a96aa3bSJed Brown 
20650a96aa3bSJed Brown   PetscFunctionBegin;
2066792fecdfSBarry Smith   PetscCallP4estReturn(refcube, p4est_connectivity_new_byname, ("unit"));
20670a96aa3bSJed Brown   { /* [-1,1]^d geometry */
20680a96aa3bSJed Brown     PetscInt i, j;
20690a96aa3bSJed Brown 
20700a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
20710a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
20720a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
20730a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
20740a96aa3bSJed Brown       }
20750a96aa3bSJed Brown     }
20760a96aa3bSJed Brown   }
2077792fecdfSBarry Smith   PetscCallP4estReturn(root, p4est_new, (comm_self, refcube, 0, NULL, NULL));
2078792fecdfSBarry Smith   PetscCallP4estReturn(refined, p4est_new_ext, (comm_self, refcube, 0, 1, 1, 0, NULL, NULL));
20799566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(root, &dmRoot));
20809566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(refined, &dmRefined));
20810a96aa3bSJed Brown   {
20820a96aa3bSJed Brown   #if !defined(P4_TO_P8)
20830a96aa3bSJed Brown     PetscInt nPoints   = 25;
20849371c9d4SSatish 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};
20859371c9d4SSatish 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};
20860a96aa3bSJed Brown   #else
20870a96aa3bSJed Brown     PetscInt nPoints    = 125;
20889371c9d4SSatish 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,
20899371c9d4SSatish 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,
20909371c9d4SSatish 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};
20919371c9d4SSatish 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,
20929371c9d4SSatish 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};
20930a96aa3bSJed Brown 
20940a96aa3bSJed Brown   #endif
20950a96aa3bSJed Brown     IS permIS;
20960a96aa3bSJed Brown     DM dmPerm;
20970a96aa3bSJed Brown 
20989566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nPoints, perm, PETSC_USE_POINTER, &permIS));
20999566063dSJacob Faibussowitsch     PetscCall(DMPlexPermute(dmRefined, permIS, &dmPerm));
21000a96aa3bSJed Brown     if (dmPerm) {
21019566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmRefined));
21020a96aa3bSJed Brown       dmRefined = dmPerm;
21030a96aa3bSJed Brown     }
21049566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
21050a96aa3bSJed Brown     {
21060a96aa3bSJed Brown       PetscInt p;
21079566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRoot, "identity"));
21089566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRefined, "identity"));
210948a46eb9SPierre Jolivet       for (p = 0; p < P4EST_INSUL; p++) PetscCall(DMSetLabelValue(dmRoot, "identity", p, p));
211048a46eb9SPierre Jolivet       for (p = 0; p < nPoints; p++) PetscCall(DMSetLabelValue(dmRefined, "identity", p, ident[p]));
21110a96aa3bSJed Brown     }
21120a96aa3bSJed Brown   }
21139566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(dmRoot, dmRefined, "identity", dm));
21140a96aa3bSJed Brown   mesh                   = (DM_Plex *)(*dm)->data;
21150a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
21169566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
21170a96aa3bSJed Brown   if (rank == 0) {
21189566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRoot, NULL, "-dm_p4est_ref_root_view"));
21199566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined, NULL, "-dm_p4est_ref_refined_view"));
21209566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined, NULL, "-dm_p4est_ref_tree_view"));
21210a96aa3bSJed Brown   }
21229566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRefined));
21239566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRoot));
2124792fecdfSBarry Smith   PetscCallP4est(p4est_destroy, (refined));
2125792fecdfSBarry Smith   PetscCallP4est(p4est_destroy, (root));
2126792fecdfSBarry Smith   PetscCallP4est(p4est_connectivity_destroy, (refcube));
21273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21280a96aa3bSJed Brown }
21290a96aa3bSJed Brown 
2130d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB)
2131d71ae5a4SJacob Faibussowitsch {
21320a96aa3bSJed Brown   void     *ctx;
21330a96aa3bSJed Brown   PetscInt  num;
21340a96aa3bSJed Brown   PetscReal val;
21350a96aa3bSJed Brown 
21360a96aa3bSJed Brown   PetscFunctionBegin;
21379566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmA, &ctx));
21389566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dmB, ctx));
21399566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmA, dmB));
21409566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dmA, &num, &val));
21419566063dSJacob Faibussowitsch   PetscCall(DMSetOutputSequenceNumber(dmB, num, val));
21420a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
21439566063dSJacob Faibussowitsch     PetscCall(DMClearLocalVectors(dmB));
21449566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->localSection));
21459566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->localSection)));
21460a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
21479566063dSJacob Faibussowitsch     PetscCall(DMClearGlobalVectors(dmB));
21489566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->globalSection));
21499566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->globalSection)));
21500a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
21519566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.section));
21529566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->defaultConstraint.section)));
21533b8ba7d1SJed Brown     dmB->defaultConstraint.section = dmA->defaultConstraint.section;
21549566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.mat));
21559566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(dmB->defaultConstraint.mat)));
21563b8ba7d1SJed Brown     dmB->defaultConstraint.mat = dmA->defaultConstraint.mat;
21579566063dSJacob Faibussowitsch     if (dmA->map) PetscCall(PetscLayoutReference(dmA->map, &dmB->map));
21580a96aa3bSJed Brown   }
21590a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
21609566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->sectionSF));
21619566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&dmB->sectionSF));
21620a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
21630a96aa3bSJed Brown   }
21643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21650a96aa3bSJed Brown }
21660a96aa3bSJed Brown 
21670a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
2168d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm, p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF)
2169d71ae5a4SJacob Faibussowitsch {
21700a96aa3bSJed Brown   PetscInt     startF, endF, startC, endC, p, nLeaves;
21710a96aa3bSJed Brown   PetscSFNode *leaves;
21720a96aa3bSJed Brown   PetscSF      sf;
21730a96aa3bSJed Brown   PetscInt    *recv, *send;
21740a96aa3bSJed Brown   PetscMPIInt  tag;
21750a96aa3bSJed Brown   MPI_Request *recvReqs, *sendReqs;
21760a96aa3bSJed Brown   PetscSection section;
21770a96aa3bSJed Brown 
21780a96aa3bSJed Brown   PetscFunctionBegin;
21799566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize, p4estC->mpirank, p4estF, p4estC, &startC, &endC));
21809566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2 * (endC - startC), &recv, endC - startC, &recvReqs));
21819566063dSJacob Faibussowitsch   PetscCall(PetscCommGetNewTag(comm, &tag));
21820a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
21830a96aa3bSJed Brown     recvReqs[p - startC] = MPI_REQUEST_NULL;                                        /* just in case we don't initiate a receive */
21840a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p + 1]) { /* empty coarse partition */
21850a96aa3bSJed Brown       recv[2 * (p - startC)]     = 0;
21860a96aa3bSJed Brown       recv[2 * (p - startC) + 1] = 0;
21870a96aa3bSJed Brown       continue;
21880a96aa3bSJed Brown     }
21890a96aa3bSJed Brown 
21909566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(&recv[2 * (p - startC)], 2, MPIU_INT, p, tag, comm, &recvReqs[p - startC]));
21910a96aa3bSJed Brown   }
21929566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize, p4estC->mpirank, p4estC, p4estF, &startF, &endF));
21939566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2 * (endF - startF), &send, endF - startF, &sendReqs));
21940a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
21950a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
21960a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
21970a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p + 1];
21980a96aa3bSJed Brown     PetscInt          tStart      = (PetscInt)myFineStart->p.which_tree;
21990a96aa3bSJed Brown     PetscInt          tEnd        = (PetscInt)myFineEnd->p.which_tree;
22000a96aa3bSJed Brown     PetscInt          firstCell = -1, lastCell = -1;
22010a96aa3bSJed Brown     p4est_tree_t     *treeStart = &(((p4est_tree_t *)p4estC->trees->array)[tStart]);
22020a96aa3bSJed Brown     p4est_tree_t     *treeEnd   = (size_t)tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t *)p4estC->trees->array)[tEnd]) : NULL;
22030a96aa3bSJed Brown     ssize_t           overlapIndex;
22040a96aa3bSJed Brown 
22050a96aa3bSJed Brown     sendReqs[p - startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
22060a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p + 1]) continue;
22070a96aa3bSJed Brown 
22080a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
22090a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
2210792fecdfSBarry Smith       PetscCallP4estReturn(overlapIndex, sc_array_bsearch, (&(treeStart->quadrants), myFineStart, p4est_quadrant_disjoint));
22110a96aa3bSJed Brown       if (overlapIndex < 0) {
22120a96aa3bSJed Brown         firstCell = 0;
22130a96aa3bSJed Brown       } else {
22140a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
22150a96aa3bSJed Brown       }
22160a96aa3bSJed Brown     } else {
22170a96aa3bSJed Brown       firstCell = 0;
22180a96aa3bSJed Brown     }
22190a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
2220792fecdfSBarry Smith       PetscCallP4estReturn(overlapIndex, sc_array_bsearch, (&(treeEnd->quadrants), myFineEnd, p4est_quadrant_disjoint));
22210a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
22220a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
22230a96aa3bSJed Brown       } else {
22240a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t *)treeEnd->quadrants.array)[overlapIndex]);
22250a96aa3bSJed Brown         p4est_quadrant_t  first_desc;
22260a96aa3bSJed Brown         int               equal;
22270a96aa3bSJed Brown 
2228792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_first_descendant, (container, &first_desc, P4EST_QMAXLEVEL));
2229792fecdfSBarry Smith         PetscCallP4estReturn(equal, p4est_quadrant_is_equal, (myFineEnd, &first_desc));
22300a96aa3bSJed Brown         if (equal) {
22310a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
22320a96aa3bSJed Brown         } else {
22330a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
22340a96aa3bSJed Brown         }
22350a96aa3bSJed Brown       }
22360a96aa3bSJed Brown     } else {
22370a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
22380a96aa3bSJed Brown     }
22390a96aa3bSJed Brown     send[2 * (p - startF)]     = firstCell;
22400a96aa3bSJed Brown     send[2 * (p - startF) + 1] = lastCell - firstCell;
22419566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(&send[2 * (p - startF)], 2, MPIU_INT, p, tag, comm, &sendReqs[p - startF]));
22420a96aa3bSJed Brown   }
22439566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endC - startC), recvReqs, MPI_STATUSES_IGNORE));
22449566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
22459566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, startC, endC));
22460a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22470a96aa3bSJed Brown     PetscInt numCells = recv[2 * (p - startC) + 1];
22489566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section, p, numCells));
22490a96aa3bSJed Brown   }
22509566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
22519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &nLeaves));
22529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nLeaves, &leaves));
22530a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22540a96aa3bSJed Brown     PetscInt firstCell = recv[2 * (p - startC)];
22550a96aa3bSJed Brown     PetscInt numCells  = recv[2 * (p - startC) + 1];
22560a96aa3bSJed Brown     PetscInt off, i;
22570a96aa3bSJed Brown 
22589566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
22590a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
22600a96aa3bSJed Brown       leaves[off + i].rank  = p;
22610a96aa3bSJed Brown       leaves[off + i].index = firstCell + i;
22620a96aa3bSJed Brown     }
22630a96aa3bSJed Brown   }
22649566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf));
22659566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, cEnd - cStart, nLeaves, NULL, PETSC_OWN_POINTER, leaves, PETSC_OWN_POINTER));
22669566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
22679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endF - startF), sendReqs, MPI_STATUSES_IGNORE));
22689566063dSJacob Faibussowitsch   PetscCall(PetscFree2(send, sendReqs));
22699566063dSJacob Faibussowitsch   PetscCall(PetscFree2(recv, recvReqs));
22700a96aa3bSJed Brown   *coveringSF = sf;
22713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22720a96aa3bSJed Brown }
22730a96aa3bSJed Brown 
22740a96aa3bSJed Brown /* closure points for locally-owned cells */
2275d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints, PetscBool redirect)
2276d71ae5a4SJacob Faibussowitsch {
22770a96aa3bSJed Brown   PetscInt           cStart, cEnd;
22780a96aa3bSJed Brown   PetscInt           count, c;
22790a96aa3bSJed Brown   PetscMPIInt        rank;
22800a96aa3bSJed Brown   PetscInt           closureSize = -1;
22810a96aa3bSJed Brown   PetscInt          *closure     = NULL;
22820a96aa3bSJed Brown   PetscSF            pointSF;
22830a96aa3bSJed Brown   PetscInt           nleaves, nroots;
22840a96aa3bSJed Brown   const PetscInt    *ilocal;
22850a96aa3bSJed Brown   const PetscSFNode *iremote;
22860a96aa3bSJed Brown   DM                 plex;
22870a96aa3bSJed Brown   DM_Forest         *forest;
22880a96aa3bSJed Brown   DM_Forest_pforest *pforest;
22890a96aa3bSJed Brown 
22900a96aa3bSJed Brown   PetscFunctionBegin;
22910a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
22920a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
22930a96aa3bSJed Brown   cStart  = pforest->cLocalStart;
22940a96aa3bSJed Brown   cEnd    = pforest->cLocalEnd;
22959566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
22969566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &pointSF));
22979566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &ilocal, &iremote));
22980a96aa3bSJed Brown   nleaves           = PetscMax(0, nleaves);
22990a96aa3bSJed Brown   nroots            = PetscMax(0, nroots);
23000a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
23019566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numClosurePoints, closurePoints));
23029566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
23030a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
23040a96aa3bSJed Brown     PetscInt i;
23059566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(plex, c, PETSC_TRUE, &closureSize, &closure));
23060a96aa3bSJed Brown 
23070a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
23080a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
23090a96aa3bSJed Brown       PetscInt loc = -1;
23100a96aa3bSJed Brown 
23119566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(p, nleaves, ilocal, &loc));
23120a96aa3bSJed Brown       if (redirect && loc >= 0) {
23130a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
23140a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
23150a96aa3bSJed Brown       } else {
23160a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
23170a96aa3bSJed Brown         (*closurePoints)[count].index = p;
23180a96aa3bSJed Brown       }
23190a96aa3bSJed Brown     }
23209566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(plex, c, PETSC_TRUE, &closureSize, &closure));
23210a96aa3bSJed Brown   }
23223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23230a96aa3bSJed Brown }
23240a96aa3bSJed Brown 
2325d71ae5a4SJacob Faibussowitsch static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type)
2326d71ae5a4SJacob Faibussowitsch {
23270a96aa3bSJed Brown   PetscMPIInt i;
23280a96aa3bSJed Brown 
23290a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
23300a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode *)a;
23310a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode *)b;
23320a96aa3bSJed Brown 
23330a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
23340a96aa3bSJed Brown   }
23350a96aa3bSJed Brown }
23360a96aa3bSJed Brown 
2337d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
2338d71ae5a4SJacob Faibussowitsch {
23390a96aa3bSJed Brown   MPI_Comm           comm;
23400a96aa3bSJed Brown   PetscMPIInt        rank, size;
23410a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
23420a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
23430a96aa3bSJed Brown   PetscInt           numClosureIndices;
23440a96aa3bSJed Brown   PetscInt           numClosurePointsC, numClosurePointsF;
23450a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
23460a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
23470a96aa3bSJed Brown   p4est_quadrant_t **treeQuads;
23480a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
23490a96aa3bSJed Brown   MPI_Datatype       nodeType;
23500a96aa3bSJed Brown   MPI_Datatype       nodeClosureType;
23510a96aa3bSJed Brown   MPI_Op             sfNodeReduce;
23520a96aa3bSJed Brown   p4est_topidx_t     fltF, lltF, t;
23530a96aa3bSJed Brown   DM                 plexC, plexF;
23540a96aa3bSJed Brown   PetscInt           pStartF, pEndF, pStartC, pEndC;
23550a96aa3bSJed Brown   PetscBool          saveInCoarse = PETSC_FALSE;
23560a96aa3bSJed Brown   PetscBool          saveInFine   = PETSC_FALSE;
23570a96aa3bSJed Brown   PetscBool          formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
23580a96aa3bSJed Brown   PetscInt          *cids         = NULL;
23590a96aa3bSJed Brown 
23600a96aa3bSJed Brown   PetscFunctionBegin;
23610a96aa3bSJed Brown   pforestC = (DM_Forest_pforest *)((DM_Forest *)coarse->data)->data;
23620a96aa3bSJed Brown   pforestF = (DM_Forest_pforest *)((DM_Forest *)fine->data)->data;
23630a96aa3bSJed Brown   p4estC   = pforestC->forest;
23640a96aa3bSJed Brown   p4estF   = pforestF->forest;
236508401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo, PetscObjectComm((PetscObject)coarse), PETSC_ERR_ARG_INCOMP, "DM's must have the same base DM");
23660a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
23679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
23689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
23699566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine, &plexF));
23709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF, &pStartF, &pEndF));
23719566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse, &plexC));
23729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC, &pStartC, &pEndC));
23730a96aa3bSJed Brown   { /* check if the results have been cached */
23740a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
23750a96aa3bSJed Brown 
23769566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(coarse, &adaptCoarse));
23779566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(fine, &adaptFine));
23780a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
23790a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
23809566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestC->pointSelfToAdaptSF)));
23810a96aa3bSJed Brown         *sf = pforestC->pointSelfToAdaptSF;
23820a96aa3bSJed Brown         if (childIds) {
23839566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
23849566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids, pforestC->pointSelfToAdaptCids, pEndF - pStartF));
23850a96aa3bSJed Brown           *childIds = cids;
23860a96aa3bSJed Brown         }
23873ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
23880a96aa3bSJed Brown       } else {
23890a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
23900a96aa3bSJed Brown         formCids     = PETSC_TRUE;
23910a96aa3bSJed Brown       }
23920a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
23930a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
23949566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestF->pointAdaptToSelfSF)));
23950a96aa3bSJed Brown         *sf = pforestF->pointAdaptToSelfSF;
23960a96aa3bSJed Brown         if (childIds) {
23979566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
23989566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids, pforestF->pointAdaptToSelfCids, pEndF - pStartF));
23990a96aa3bSJed Brown           *childIds = cids;
24000a96aa3bSJed Brown         }
24013ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
24020a96aa3bSJed Brown       } else {
24030a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
24040a96aa3bSJed Brown         formCids   = PETSC_TRUE;
24050a96aa3bSJed Brown       }
24060a96aa3bSJed Brown     }
24070a96aa3bSJed Brown   }
24080a96aa3bSJed Brown 
24090a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
24100a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
24110a96aa3bSJed Brown   /* create the datatype */
24129566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(2, MPIU_INT, &nodeType));
24139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
24149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_create(DMPforestMaxSFNode, PETSC_FALSE, &sfNodeReduce));
24159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(numClosureIndices * 2, MPIU_INT, &nodeClosureType));
24169566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeClosureType));
24170a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
24180a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
24199566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(coarse, numClosureIndices, &numClosurePointsC, &closurePointsC, PETSC_TRUE));
24209566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(fine, numClosureIndices, &numClosurePointsF, &closurePointsF, PETSC_FALSE));
24210a96aa3bSJed Brown   /* create pointers for tree lists */
24220a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
24230a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
24249566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(lltF + 1 - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts));
24250a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
24260a96aa3bSJed Brown   if (size > 1) {
24270a96aa3bSJed Brown     PetscInt p;
24280a96aa3bSJed Brown 
24290a96aa3bSJed Brown     for (p = 0; p < size; p++) {
24300a96aa3bSJed Brown       int equal;
24310a96aa3bSJed Brown 
2432792fecdfSBarry Smith       PetscCallP4estReturn(equal, p4est_quadrant_is_equal_piggy, (&p4estC->global_first_position[p], &p4estF->global_first_position[p]));
24330a96aa3bSJed Brown       if (!equal) break;
24340a96aa3bSJed Brown     }
24350a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
24360a96aa3bSJed Brown       PetscInt          cStartC, cEndC;
24370a96aa3bSJed Brown       PetscSF           coveringSF;
24380a96aa3bSJed Brown       PetscInt          nleaves;
24390a96aa3bSJed Brown       PetscInt          count;
24400a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
24410a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
24420a96aa3bSJed Brown       p4est_topidx_t    fltC = p4estC->first_local_tree;
24430a96aa3bSJed Brown       p4est_topidx_t    lltC = p4estC->last_local_tree;
24440a96aa3bSJed Brown       p4est_topidx_t    t;
24450a96aa3bSJed Brown       PetscMPIInt       blockSizes[4]   = {P4EST_DIM, 2, 1, 1};
24469371c9d4SSatish 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)};
24470a96aa3bSJed Brown       MPI_Datatype      blockTypes[4]   = {MPI_INT32_T, MPI_INT8_T, MPI_INT16_T, MPI_INT32_T /* p.which_tree */};
24480a96aa3bSJed Brown       MPI_Datatype      quadStruct, quadType;
24490a96aa3bSJed Brown 
24509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC, 0, &cStartC, &cEndC));
24519566063dSJacob Faibussowitsch       PetscCall(DMPforestGetCellCoveringSF(comm, p4estC, p4estF, pforestC->cLocalStart, pforestC->cLocalEnd, &coveringSF));
24529566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coveringSF, NULL, &nleaves, NULL, NULL));
24539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numClosureIndices * nleaves, &newClosurePointsC));
24549566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &coverQuads));
24559566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cEndC - cStartC, &coverQuadsSend));
24560a96aa3bSJed Brown       count = 0;
24570a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
24580a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t *)p4estC->trees->array)[t]);
24590a96aa3bSJed Brown         PetscInt      q;
24600a96aa3bSJed Brown 
24619566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&coverQuadsSend[count], tree->quadrants.array, tree->quadrants.elem_count * sizeof(p4est_quadrant_t)));
24620a96aa3bSJed Brown         for (q = 0; (size_t)q < tree->quadrants.elem_count; q++) coverQuadsSend[count + q].p.which_tree = t;
24630a96aa3bSJed Brown         count += tree->quadrants.elem_count;
24640a96aa3bSJed Brown       }
24650a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
24660a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
24670a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
24680a96aa3bSJed Brown        */
24699566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_struct(4, blockSizes, blockOffsets, blockTypes, &quadStruct));
24709566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_resized(quadStruct, 0, sizeof(p4est_quadrant_t), &quadType));
24719566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&quadType));
24729566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF, nodeClosureType, closurePointsC, newClosurePointsC, MPI_REPLACE));
24739566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF, quadType, coverQuadsSend, coverQuads, MPI_REPLACE));
24749566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF, nodeClosureType, closurePointsC, newClosurePointsC, MPI_REPLACE));
24759566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF, quadType, coverQuadsSend, coverQuads, MPI_REPLACE));
24769566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadStruct));
24779566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadType));
24789566063dSJacob Faibussowitsch       PetscCall(PetscFree(coverQuadsSend));
24799566063dSJacob Faibussowitsch       PetscCall(PetscFree(closurePointsC));
24809566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coveringSF));
24810a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
24820a96aa3bSJed Brown 
24830a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
24840a96aa3bSJed Brown       {
24850a96aa3bSJed Brown         PetscInt q;
24860a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
24870a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
24880a96aa3bSJed Brown           if (!treeQuadCounts[t - fltF]++) treeQuads[t - fltF] = &coverQuads[q];
24890a96aa3bSJed Brown         }
24900a96aa3bSJed Brown       }
24910a96aa3bSJed Brown     }
24920a96aa3bSJed Brown   }
24930a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
24940a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
24950a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t *)p4estC->trees->array)[t]);
24960a96aa3bSJed Brown 
24970a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
24980a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t *)tree->quadrants.array;
24990a96aa3bSJed Brown     }
25000a96aa3bSJed Brown   }
25010a96aa3bSJed Brown 
25020a96aa3bSJed Brown   {
25030a96aa3bSJed Brown     PetscInt     p;
25040a96aa3bSJed Brown     PetscInt     cLocalStartF;
25050a96aa3bSJed Brown     PetscSF      pointSF;
25060a96aa3bSJed Brown     PetscSFNode *roots;
25070a96aa3bSJed Brown     PetscInt    *rootType;
25080a96aa3bSJed Brown     DM           refTree = NULL;
25090a96aa3bSJed Brown     DMLabel      canonical;
25100a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
25110a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
25120a96aa3bSJed Brown     PetscInt     coarseOffset;
25130a96aa3bSJed Brown     PetscInt     numCoarseQuads;
25140a96aa3bSJed Brown 
25159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF - pStartF, &roots));
25169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF - pStartF, &rootType));
25179566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(fine, &pointSF));
25180a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
25190a96aa3bSJed Brown       roots[p - pStartF].rank  = -1;
25200a96aa3bSJed Brown       roots[p - pStartF].index = -1;
25210a96aa3bSJed Brown       rootType[p - pStartF]    = -1;
25220a96aa3bSJed Brown     }
25230a96aa3bSJed Brown     if (formCids) {
25240a96aa3bSJed Brown       PetscInt child;
25250a96aa3bSJed Brown 
25269566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
25270a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
25289566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF, &refTree));
25299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(refTree, 0, PETSC_TRUE, NULL, &rootClosure));
25300a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
25319566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, child + 1, PETSC_TRUE, NULL, &childClosures[child]));
25320a96aa3bSJed Brown       }
25339566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(refTree, "canonical", &canonical));
25340a96aa3bSJed Brown     }
25350a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
25360a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
25370a96aa3bSJed Brown       p4est_tree_t     *tree         = &(((p4est_tree_t *)p4estF->trees->array)[t]);
25380a96aa3bSJed Brown       PetscInt          numFineQuads = tree->quadrants.elem_count;
25390a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads  = treeQuads[t - fltF];
25400a96aa3bSJed Brown       p4est_quadrant_t *fineQuads    = (p4est_quadrant_t *)tree->quadrants.array;
25410a96aa3bSJed Brown       PetscInt          i, coarseCount = 0;
25420a96aa3bSJed Brown       PetscInt          offset = tree->quadrants_offset;
25430a96aa3bSJed Brown       sc_array_t        coarseQuadsArray;
25440a96aa3bSJed Brown 
25450a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
2546792fecdfSBarry Smith       PetscCallP4est(sc_array_init_data, (&coarseQuadsArray, coarseQuads, sizeof(p4est_quadrant_t), (size_t)numCoarseQuads));
25470a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
25480a96aa3bSJed Brown         PetscInt          c          = i + offset;
25490a96aa3bSJed Brown         p4est_quadrant_t *quad       = &fineQuads[i];
25500a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
25510a96aa3bSJed Brown         ssize_t           disjoint   = -1;
25520a96aa3bSJed Brown 
25530a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
25540a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
2555792fecdfSBarry Smith           PetscCallP4estReturn(disjoint, p4est_quadrant_disjoint, (quadCoarse, quad));
25560a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
25570a96aa3bSJed Brown         }
255808401ef6SPierre Jolivet         PetscCheck(disjoint == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "did not find overlapping coarse quad");
25590a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
25600a96aa3bSJed Brown           if (transferIdent) {                                                                         /* find corners */
25610a96aa3bSJed Brown             PetscInt j = 0;
25620a96aa3bSJed Brown 
25630a96aa3bSJed Brown             do {
25640a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
25650a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
25660a96aa3bSJed Brown                 int              equal;
25670a96aa3bSJed Brown 
2568792fecdfSBarry Smith                 PetscCallP4est(p4est_quadrant_corner_descendant, (quad, &cornerQuad, j, quadCoarse->level));
2569792fecdfSBarry Smith                 PetscCallP4estReturn(equal, p4est_quadrant_is_equal, (&cornerQuad, quadCoarse));
25700a96aa3bSJed Brown                 if (equal) {
25710a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
25720a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
25730a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
25740a96aa3bSJed Brown 
25750a96aa3bSJed Brown                   roots[p - pStartF]    = q;
25760a96aa3bSJed Brown                   rootType[p - pStartF] = PETSC_MAX_INT;
25770a96aa3bSJed Brown                   cids[p - pStartF]     = -1;
25780a96aa3bSJed Brown                   j++;
25790a96aa3bSJed Brown                 }
25800a96aa3bSJed Brown               }
25810a96aa3bSJed Brown               coarseCount++;
25820a96aa3bSJed Brown               disjoint = 1;
25830a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
25840a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
2585792fecdfSBarry Smith                 PetscCallP4estReturn(disjoint, p4est_quadrant_disjoint, (quadCoarse, quad));
25860a96aa3bSJed Brown               }
25870a96aa3bSJed Brown             } while (!disjoint);
25880a96aa3bSJed Brown           }
25890a96aa3bSJed Brown           continue;
25900a96aa3bSJed Brown         }
25910a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
25920a96aa3bSJed Brown           PetscInt j;
25930a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
25940a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
25950a96aa3bSJed Brown 
25960a96aa3bSJed Brown             roots[p - pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
25970a96aa3bSJed Brown             rootType[p - pStartF] = PETSC_MAX_INT; /* unconditionally accept */
25980a96aa3bSJed Brown             cids[p - pStartF]     = -1;
25990a96aa3bSJed Brown           }
26000a96aa3bSJed Brown         } else {
26010a96aa3bSJed Brown           PetscInt levelDiff                 = quad->level - quadCoarse->level;
26020a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
26030a96aa3bSJed Brown 
26040a96aa3bSJed Brown           if (formCids) {
26050a96aa3bSJed Brown             PetscInt  cl;
26060a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
26070a96aa3bSJed Brown             int       cid;
26080a96aa3bSJed Brown 
260908401ef6SPierre Jolivet             PetscCheck(levelDiff <= 1, PETSC_COMM_SELF, PETSC_ERR_USER, "Recursive child ids not implemented");
2610792fecdfSBarry Smith             PetscCallP4estReturn(cid, p4est_quadrant_child_id, (quad));
26119566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(plexF, c + cLocalStartF, PETSC_TRUE, NULL, &pointClosure));
26120a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
26130a96aa3bSJed Brown               PetscInt       p      = pointClosure[2 * cl];
26140a96aa3bSJed Brown               PetscInt       point  = childClosures[cid][2 * cl];
26150a96aa3bSJed Brown               PetscInt       ornt   = childClosures[cid][2 * cl + 1];
26160a96aa3bSJed Brown               PetscInt       newcid = -1;
26170a96aa3bSJed Brown               DMPolytopeType ct;
26180a96aa3bSJed Brown 
26190a96aa3bSJed Brown               if (rootType[p - pStartF] == PETSC_MAX_INT) continue;
26209566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCellType(refTree, point, &ct));
26210a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
26220a96aa3bSJed Brown               if (!cl) {
26230a96aa3bSJed Brown                 newcid = cid + 1;
26240a96aa3bSJed Brown               } else {
26250a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
26260a96aa3bSJed Brown 
26279566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetTreeParent(refTree, point, &parent, NULL));
26280a96aa3bSJed Brown                 if (parent == point) {
26290a96aa3bSJed Brown                   newcid = -1;
26300a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
26310a96aa3bSJed Brown                   newcid = point;
26320a96aa3bSJed Brown                 } else {
26330a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
26340a96aa3bSJed Brown 
26350a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
26360a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
26379566063dSJacob Faibussowitsch                       PetscCall(DMPlexGetCellType(refTree, parent, &rct));
26380a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
26390a96aa3bSJed Brown                       break;
26400a96aa3bSJed Brown                     }
26410a96aa3bSJed Brown                   }
264208401ef6SPierre Jolivet                   PetscCheck(rcl < P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Couldn't find parent in root closure");
26439566063dSJacob Faibussowitsch                   PetscCall(DMPlexReferenceTreeGetChildSymmetry(refTree, parent, parentOrnt, ornt, point, DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]), NULL, &newcid));
26440a96aa3bSJed Brown                 }
26450a96aa3bSJed Brown               }
26460a96aa3bSJed Brown               if (newcid >= 0) {
264748a46eb9SPierre Jolivet                 if (canonical) PetscCall(DMLabelGetValue(canonical, newcid, &newcid));
26480a96aa3bSJed Brown                 proposedCids[cl] = newcid;
26490a96aa3bSJed Brown               }
26500a96aa3bSJed Brown             }
26519566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(plexF, c + cLocalStartF, PETSC_TRUE, NULL, &pointClosure));
26520a96aa3bSJed Brown           }
26539371c9d4SSatish Balay           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {
26549371c9d4SSatish Balay             {quadCoarse->x, quadCoarse->y,
26550a96aa3bSJed Brown   #if defined(P4_TO_P8)
26560a96aa3bSJed Brown              quadCoarse->z
26570a96aa3bSJed Brown   #endif
26589371c9d4SSatish Balay             },
26599371c9d4SSatish Balay             {0}
26609371c9d4SSatish Balay           };
26619371c9d4SSatish Balay           p4est_qcoord_t fineBound[2][P4EST_DIM] = {
26629371c9d4SSatish Balay             {quad->x, quad->y,
26630a96aa3bSJed Brown   #if defined(P4_TO_P8)
26640a96aa3bSJed Brown              quad->z
26650a96aa3bSJed Brown   #endif
26669371c9d4SSatish Balay             },
26679371c9d4SSatish Balay             {0}
26689371c9d4SSatish Balay           };
26690a96aa3bSJed Brown           PetscInt j;
26700a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
26710a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
26720a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j] + P4EST_QUADRANT_LEN(quad->level);
26730a96aa3bSJed Brown           }
26740a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
26750a96aa3bSJed Brown             PetscInt    l, p;
26760a96aa3bSJed Brown             PetscSFNode q;
26770a96aa3bSJed Brown 
26780a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
26790a96aa3bSJed Brown             if (rootType[p - pStartF] == PETSC_MAX_INT) continue;
26800a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
26810a96aa3bSJed Brown               l = 0;
26820a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
26830a96aa3bSJed Brown               PetscInt face       = PetscFaceToP4estFace[j - 1];
26840a96aa3bSJed Brown               PetscInt direction  = face / 2;
26850a96aa3bSJed Brown               PetscInt coarseFace = -1;
26860a96aa3bSJed Brown 
26870a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
26880a96aa3bSJed Brown                 coarseFace = face;
26890a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
26900a96aa3bSJed Brown               } else {
26910a96aa3bSJed Brown                 l = 0;
26920a96aa3bSJed Brown               }
26930a96aa3bSJed Brown   #if defined(P4_TO_P8)
26940a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
26950a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
26960a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
26970a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
26980a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
26990a96aa3bSJed Brown               PetscInt  minDir = PetscMin((direction + 1) % 3, (direction + 2) % 3);
27000a96aa3bSJed Brown               PetscInt  maxDir = PetscMax((direction + 1) % 3, (direction + 2) % 3);
27010a96aa3bSJed Brown               PetscBool dirTest[2];
27020a96aa3bSJed Brown 
27030a96aa3bSJed Brown               dirTest[0] = (PetscBool)(coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
27040a96aa3bSJed Brown               dirTest[1] = (PetscBool)(coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
27050a96aa3bSJed Brown 
27060a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
27070a96aa3bSJed Brown                 coarseEdge = edge;
27080a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27090a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
27100a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
27110a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
27120a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
27130a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
27140a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
27150a96aa3bSJed Brown               } else {
27160a96aa3bSJed Brown                 l = 0;
27170a96aa3bSJed Brown               }
27180a96aa3bSJed Brown   #endif
27190a96aa3bSJed Brown             } else {
27200a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
27210a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
27220a96aa3bSJed Brown               PetscInt  m;
27230a96aa3bSJed Brown               PetscInt  numMatch     = 0;
27240a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
27250a96aa3bSJed Brown   #if defined(P4_TO_P8)
27260a96aa3bSJed Brown               PetscInt coarseEdge = -1;
27270a96aa3bSJed Brown   #endif
27280a96aa3bSJed Brown 
27290a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
27300a96aa3bSJed Brown                 dirTest[m] = (PetscBool)(coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
27310a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
27320a96aa3bSJed Brown               }
27330a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
27340a96aa3bSJed Brown                 coarseVertex = vertex;
27350a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
27360a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
27370a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27380a96aa3bSJed Brown                   if (dirTest[m]) {
27390a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
27400a96aa3bSJed Brown                     break;
27410a96aa3bSJed Brown                   }
27420a96aa3bSJed Brown                 }
27430a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27440a96aa3bSJed Brown   #if defined(P4_TO_P8)
27450a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
27460a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27470a96aa3bSJed Brown                   if (!dirTest[m]) {
27480a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
27490a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
27500a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1, otherDir2);
27510a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1, otherDir2);
27520a96aa3bSJed Brown 
27530a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
27540a96aa3bSJed Brown                     break;
27550a96aa3bSJed Brown                   }
27560a96aa3bSJed Brown                 }
27570a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27580a96aa3bSJed Brown   #endif
27590a96aa3bSJed Brown               } else { /* volume */
27600a96aa3bSJed Brown                 l = 0;
27610a96aa3bSJed Brown               }
27620a96aa3bSJed Brown             }
27630a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
27640a96aa3bSJed Brown             if (l > rootType[p - pStartF]) {
27650a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
27660a96aa3bSJed Brown                 if (transferIdent) {
27670a96aa3bSJed Brown                   roots[p - pStartF]    = q;
27680a96aa3bSJed Brown                   rootType[p - pStartF] = PETSC_MAX_INT;
27690a96aa3bSJed Brown                   if (formCids) cids[p - pStartF] = -1;
27700a96aa3bSJed Brown                 }
27710a96aa3bSJed Brown               } else {
27720a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
27730a96aa3bSJed Brown 
27740a96aa3bSJed Brown                 roots[p - pStartF]    = q;
27750a96aa3bSJed Brown                 rootType[p - pStartF] = l;
27760a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
27770a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
27780a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
27790a96aa3bSJed Brown                   PetscInt parent;
27800a96aa3bSJed Brown 
27819566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetTreeParent(plexF, thisp, &parent, NULL));
27820a96aa3bSJed Brown                   if (parent == thisp) break;
27830a96aa3bSJed Brown 
27840a96aa3bSJed Brown                   roots[parent - pStartF]    = q;
27850a96aa3bSJed Brown                   rootType[parent - pStartF] = PETSC_MAX_INT;
27860a96aa3bSJed Brown                   if (formCids) cids[parent - pStartF] = -1;
27870a96aa3bSJed Brown                   thisp = parent;
27880a96aa3bSJed Brown                 }
27890a96aa3bSJed Brown               }
27900a96aa3bSJed Brown             }
27910a96aa3bSJed Brown           }
27920a96aa3bSJed Brown         }
27930a96aa3bSJed Brown       }
27940a96aa3bSJed Brown     }
27950a96aa3bSJed Brown 
27960a96aa3bSJed 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 */
27970a96aa3bSJed Brown     if (size > 1) {
27980a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
27990a96aa3bSJed Brown 
28009566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &rootTypeCopy));
28019566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(rootTypeCopy, rootType, pEndF - pStartF));
280257168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_MAX));
280357168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_MAX));
28049566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_REPLACE));
28059566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_REPLACE));
28060a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28070a96aa3bSJed 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 */
28080a96aa3bSJed Brown           roots[p - pStartF].rank  = -1;
28090a96aa3bSJed Brown           roots[p - pStartF].index = -1;
28100a96aa3bSJed Brown         }
28119371c9d4SSatish 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 */ }
28120a96aa3bSJed Brown       }
28139566063dSJacob Faibussowitsch       PetscCall(PetscFree(rootTypeCopy));
28149566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF, nodeType, roots, roots, sfNodeReduce));
28159566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF, nodeType, roots, roots, sfNodeReduce));
28169566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, nodeType, roots, roots, MPI_REPLACE));
28179566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, nodeType, roots, roots, MPI_REPLACE));
28180a96aa3bSJed Brown     }
28199566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootType));
28200a96aa3bSJed Brown 
28210a96aa3bSJed Brown     {
28220a96aa3bSJed Brown       PetscInt     numRoots;
28230a96aa3bSJed Brown       PetscInt     numLeaves;
28240a96aa3bSJed Brown       PetscInt    *leaves;
28250a96aa3bSJed Brown       PetscSFNode *iremote;
28260a96aa3bSJed Brown       /* count leaves */
28270a96aa3bSJed Brown 
28280a96aa3bSJed Brown       numRoots = pEndC - pStartC;
28290a96aa3bSJed Brown 
28300a96aa3bSJed Brown       numLeaves = 0;
28310a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28320a96aa3bSJed Brown         if (roots[p - pStartF].index >= 0) numLeaves++;
28330a96aa3bSJed Brown       }
28349566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves, &leaves));
28359566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves, &iremote));
28360a96aa3bSJed Brown       numLeaves = 0;
28370a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28380a96aa3bSJed Brown         if (roots[p - pStartF].index >= 0) {
28390a96aa3bSJed Brown           leaves[numLeaves]  = p - pStartF;
28400a96aa3bSJed Brown           iremote[numLeaves] = roots[p - pStartF];
28410a96aa3bSJed Brown           numLeaves++;
28420a96aa3bSJed Brown         }
28430a96aa3bSJed Brown       }
28449566063dSJacob Faibussowitsch       PetscCall(PetscFree(roots));
28459566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, sf));
28460a96aa3bSJed Brown       if (numLeaves == (pEndF - pStartF)) {
28479566063dSJacob Faibussowitsch         PetscCall(PetscFree(leaves));
28489566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf, numRoots, numLeaves, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
28490a96aa3bSJed Brown       } else {
28509566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf, numRoots, numLeaves, leaves, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
28510a96aa3bSJed Brown       }
28520a96aa3bSJed Brown     }
28530a96aa3bSJed Brown     if (formCids) {
28540a96aa3bSJed Brown       PetscSF  pointSF;
28550a96aa3bSJed Brown       PetscInt child;
28560a96aa3bSJed Brown 
28579566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF, &refTree));
28589566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(plexF, &pointSF));
285957168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, cids, cids, MPI_MAX));
286057168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, cids, cids, MPI_MAX));
28610a96aa3bSJed Brown       if (childIds) *childIds = cids;
286248a46eb9SPierre Jolivet       for (child = 0; child < P4EST_CHILDREN; child++) PetscCall(DMPlexRestoreTransitiveClosure(refTree, child + 1, PETSC_TRUE, NULL, &childClosures[child]));
28639566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(refTree, 0, PETSC_TRUE, NULL, &rootClosure));
28640a96aa3bSJed Brown     }
28650a96aa3bSJed Brown   }
28660a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
28679566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
28680a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
28690a96aa3bSJed Brown     if (!childIds) {
28700a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
28710a96aa3bSJed Brown     } else {
28729566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &pforestC->pointSelfToAdaptCids));
28739566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestC->pointSelfToAdaptCids, cids, pEndF - pStartF));
28740a96aa3bSJed Brown     }
28750a96aa3bSJed Brown   } else if (saveInFine) {
28769566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
28770a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
28780a96aa3bSJed Brown     if (!childIds) {
28790a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
28800a96aa3bSJed Brown     } else {
28819566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &pforestF->pointAdaptToSelfCids));
28829566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestF->pointAdaptToSelfCids, cids, pEndF - pStartF));
28830a96aa3bSJed Brown     }
28840a96aa3bSJed Brown   }
28859566063dSJacob Faibussowitsch   PetscCall(PetscFree2(treeQuads, treeQuadCounts));
28869566063dSJacob Faibussowitsch   PetscCall(PetscFree(coverQuads));
28879566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsC));
28889566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsF));
28899566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeClosureType));
28909566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_free(&sfNodeReduce));
28919566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
28923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28930a96aa3bSJed Brown }
28940a96aa3bSJed Brown 
28950a96aa3bSJed Brown /* children are sf leaves of parents */
2896d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
2897d71ae5a4SJacob Faibussowitsch {
28980a96aa3bSJed Brown   MPI_Comm           comm;
2899d70f29a3SPierre Jolivet   PetscMPIInt        rank;
29000a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
29010a96aa3bSJed Brown   DM                 plexC, plexF;
29020a96aa3bSJed Brown   PetscInt           pStartC, pEndC, pStartF, pEndF;
29030a96aa3bSJed Brown   PetscSF            pointTransferSF;
29040a96aa3bSJed Brown   PetscBool          allOnes = PETSC_TRUE;
29050a96aa3bSJed Brown 
29060a96aa3bSJed Brown   PetscFunctionBegin;
29070a96aa3bSJed Brown   pforestC = (DM_Forest_pforest *)((DM_Forest *)coarse->data)->data;
29080a96aa3bSJed Brown   pforestF = (DM_Forest_pforest *)((DM_Forest *)fine->data)->data;
290908401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo, PetscObjectComm((PetscObject)coarse), PETSC_ERR_ARG_INCOMP, "DM's must have the same base DM");
29100a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
29119566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
29120a96aa3bSJed Brown 
29130a96aa3bSJed Brown   {
29140a96aa3bSJed Brown     PetscInt i;
29150a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
29160a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
29170a96aa3bSJed Brown         allOnes = PETSC_FALSE;
29180a96aa3bSJed Brown         break;
29190a96aa3bSJed Brown       }
29200a96aa3bSJed Brown     }
29210a96aa3bSJed Brown   }
29229566063dSJacob Faibussowitsch   PetscCall(DMPforestGetTransferSF_Point(coarse, fine, &pointTransferSF, transferIdent, childIds));
29230a96aa3bSJed Brown   if (allOnes) {
29240a96aa3bSJed Brown     *sf = pointTransferSF;
29253ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
29260a96aa3bSJed Brown   }
29270a96aa3bSJed Brown 
29289566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine, &plexF));
29299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF, &pStartF, &pEndF));
29309566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse, &plexC));
29319566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC, &pStartC, &pEndC));
29320a96aa3bSJed Brown   {
29330a96aa3bSJed Brown     PetscInt           numRoots;
29340a96aa3bSJed Brown     PetscInt           numLeaves;
29350a96aa3bSJed Brown     const PetscInt    *leaves;
29360a96aa3bSJed Brown     const PetscSFNode *iremote;
29370a96aa3bSJed Brown     PetscInt           d;
29380a96aa3bSJed Brown     PetscSection       leafSection, rootSection;
29390a96aa3bSJed Brown     /* count leaves */
29400a96aa3bSJed Brown 
29419566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointTransferSF, &numRoots, &numLeaves, &leaves, &iremote));
29429566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &rootSection));
29439566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &leafSection));
29449566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(rootSection, pStartC, pEndC));
29459566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(leafSection, pStartF, pEndF));
29460a96aa3bSJed Brown 
29470a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
29480a96aa3bSJed Brown       PetscInt startC, endC, e;
29490a96aa3bSJed Brown 
29509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC, P4EST_DIM - d, &startC, &endC));
295148a46eb9SPierre Jolivet       for (e = startC; e < endC; e++) PetscCall(PetscSectionSetDof(rootSection, e, dofPerDim[d]));
29520a96aa3bSJed Brown     }
29530a96aa3bSJed Brown 
29540a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
29550a96aa3bSJed Brown       PetscInt startF, endF, e;
29560a96aa3bSJed Brown 
29579566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexF, P4EST_DIM - d, &startF, &endF));
295848a46eb9SPierre Jolivet       for (e = startF; e < endF; e++) PetscCall(PetscSectionSetDof(leafSection, e, dofPerDim[d]));
29590a96aa3bSJed Brown     }
29600a96aa3bSJed Brown 
29619566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(rootSection));
29629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafSection));
29630a96aa3bSJed Brown     {
29640a96aa3bSJed Brown       PetscInt     nroots, nleaves;
29650a96aa3bSJed Brown       PetscInt    *mine, i, p;
29660a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
29670a96aa3bSJed Brown       PetscSFNode *remote;
29680a96aa3bSJed Brown 
29699566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &offsets));
29709566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndC - pStartC, &offsetsRoot));
297148a46eb9SPierre Jolivet       for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionGetOffset(rootSection, p, &offsetsRoot[p - pStartC]));
29729566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointTransferSF, MPIU_INT, offsetsRoot, offsets, MPI_REPLACE));
29739566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointTransferSF, MPIU_INT, offsetsRoot, offsets, MPI_REPLACE));
29749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(rootSection, &nroots));
29750a96aa3bSJed Brown       nleaves = 0;
29760a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
29770a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
29780a96aa3bSJed Brown         PetscInt dof;
29790a96aa3bSJed Brown 
29809566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection, leaf, &dof));
29810a96aa3bSJed Brown         nleaves += dof;
29820a96aa3bSJed Brown       }
29839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &mine));
29849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &remote));
29850a96aa3bSJed Brown       nleaves = 0;
29860a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
29870a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
29880a96aa3bSJed Brown         PetscInt dof;
29890a96aa3bSJed Brown         PetscInt off, j;
29900a96aa3bSJed Brown 
29919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection, leaf, &dof));
29929566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafSection, leaf, &off));
29930a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
29940a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
29950a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
29960a96aa3bSJed Brown           mine[nleaves++]       = off + j;
29970a96aa3bSJed Brown         }
29980a96aa3bSJed Brown       }
29999566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsetsRoot));
30009566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsets));
30019566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, sf));
30029566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
30030a96aa3bSJed Brown     }
30049566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
30059566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootSection));
30069566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointTransferSF));
30070a96aa3bSJed Brown   }
30083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30090a96aa3bSJed Brown }
30100a96aa3bSJed Brown 
3011d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA)
3012d71ae5a4SJacob Faibussowitsch {
30130a96aa3bSJed Brown   DM          adaptA, adaptB;
30140a96aa3bSJed Brown   DMAdaptFlag purpose;
30150a96aa3bSJed Brown 
30160a96aa3bSJed Brown   PetscFunctionBegin;
30179566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmA, &adaptA));
30189566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmB, &adaptB));
30190a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
30200a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
30219566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmA, &purpose));
30220a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
30239566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30243ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
30250a96aa3bSJed Brown     }
30260a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
30279566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmB, &purpose));
30280a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
30299566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30303ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
30310a96aa3bSJed Brown     }
30320a96aa3bSJed Brown   }
30331baa6e33SBarry Smith   if (sfAtoB) PetscCall(DMPforestGetTransferSF_Internal(dmA, dmB, dofPerDim, sfAtoB, PETSC_TRUE, NULL));
30341baa6e33SBarry Smith   if (sfBtoA) PetscCall(DMPforestGetTransferSF_Internal(dmB, dmA, dofPerDim, sfBtoA, (PetscBool)(sfAtoB == NULL), NULL));
30353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30360a96aa3bSJed Brown }
30370a96aa3bSJed Brown 
3038d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex)
3039d71ae5a4SJacob Faibussowitsch {
30400a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
30410a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
30420a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
30430a96aa3bSJed Brown   PetscInt           cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
30440a96aa3bSJed Brown   PetscInt           pStart, pEnd, pStartBase, pEndBase, p;
30450a96aa3bSJed Brown   DM                 base;
30460a96aa3bSJed Brown   PetscInt          *star      = NULL, starSize;
30470a96aa3bSJed Brown   DMLabelLink        next      = dm->labels;
30480a96aa3bSJed Brown   PetscInt           guess     = 0;
30490a96aa3bSJed Brown   p4est_topidx_t     num_trees = pforest->topo->conn->num_trees;
30500a96aa3bSJed Brown 
30510a96aa3bSJed Brown   PetscFunctionBegin;
30520a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
30530a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
30540a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
30559566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
30560a96aa3bSJed Brown   if (!base) {
30570a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
30580a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
30590a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
30600a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t *)p4est->trees->array;
30610a96aa3bSJed Brown       p4est_topidx_t        t, flt = p4est->first_local_tree;
30620a96aa3bSJed Brown       p4est_topidx_t        llt = pforest->forest->last_local_tree;
30630a96aa3bSJed Brown       DMLabel               ghostLabel;
30640a96aa3bSJed Brown       PetscInt              c;
30650a96aa3bSJed Brown 
30669566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(plex, pforest->ghostName));
30679566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(plex, pforest->ghostName, &ghostLabel));
30680a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
30690a96aa3bSJed Brown         p4est_tree_t     *tree     = &trees[t];
30700a96aa3bSJed Brown         p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
30710a96aa3bSJed Brown         PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
30720a96aa3bSJed Brown         PetscInt          q;
30730a96aa3bSJed Brown 
30740a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
30750a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
30760a96aa3bSJed Brown           PetscInt          f;
30770a96aa3bSJed Brown 
30780a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
30790a96aa3bSJed Brown             p4est_quadrant_t neigh;
30800a96aa3bSJed Brown             int              isOutside;
30810a96aa3bSJed Brown 
3082792fecdfSBarry Smith             PetscCallP4est(p4est_quadrant_face_neighbor, (quad, f, &neigh));
3083792fecdfSBarry Smith             PetscCallP4estReturn(isOutside, p4est_quadrant_is_outside_face, (&neigh));
30840a96aa3bSJed Brown             if (isOutside) {
30850a96aa3bSJed Brown               p4est_topidx_t nt;
30860a96aa3bSJed Brown               PetscInt       nf;
30870a96aa3bSJed Brown 
30880a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
30890a96aa3bSJed Brown               nf = (PetscInt)conn->tree_to_face[t * P4EST_FACES + f];
30900a96aa3bSJed Brown               nf = nf % P4EST_FACES;
30910a96aa3bSJed Brown               if (nt == t && nf == f) {
30920a96aa3bSJed Brown                 PetscInt        plexF = P4estFaceToPetscFace[f];
30930a96aa3bSJed Brown                 const PetscInt *cone;
30940a96aa3bSJed Brown 
30959566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetCone(plex, c, &cone));
30969566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(ghostLabel, cone[plexF], plexF + 1));
30970a96aa3bSJed Brown               }
30980a96aa3bSJed Brown             }
30990a96aa3bSJed Brown           }
31000a96aa3bSJed Brown         }
31010a96aa3bSJed Brown       }
31020a96aa3bSJed Brown     }
31033ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
31040a96aa3bSJed Brown   }
31059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, 0, &cStartBase, &cEndBase));
31069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, 1, &fStartBase, &fEndBase));
31079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, P4EST_DIM - 1, &eStartBase, &eEndBase));
31089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(base, 0, &vStartBase, &vEndBase));
31090a96aa3bSJed Brown 
31109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd));
31119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 1, &fStart, &fEnd));
31129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, P4EST_DIM - 1, &eStart, &eEnd));
31139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
31140a96aa3bSJed Brown 
31159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &pStart, &pEnd));
31169566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(base, &pStartBase, &pEndBase));
31170a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
31180a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
31190a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
31200a96aa3bSJed Brown   while (next) {
31210a96aa3bSJed Brown     DMLabel     baseLabel;
31220a96aa3bSJed Brown     DMLabel     label = next->label;
31230a96aa3bSJed Brown     PetscBool   isDepth, isCellType, isGhost, isVTK, isSpmap;
31240a96aa3bSJed Brown     const char *name;
31250a96aa3bSJed Brown 
31269566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)label, &name));
31279566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "depth", &isDepth));
31280a96aa3bSJed Brown     if (isDepth) {
31290a96aa3bSJed Brown       next = next->next;
31300a96aa3bSJed Brown       continue;
31310a96aa3bSJed Brown     }
31329566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "celltype", &isCellType));
31330a96aa3bSJed Brown     if (isCellType) {
31340a96aa3bSJed Brown       next = next->next;
31350a96aa3bSJed Brown       continue;
31360a96aa3bSJed Brown     }
31379566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "ghost", &isGhost));
31380a96aa3bSJed Brown     if (isGhost) {
31390a96aa3bSJed Brown       next = next->next;
31400a96aa3bSJed Brown       continue;
31410a96aa3bSJed Brown     }
31429566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "vtk", &isVTK));
31430a96aa3bSJed Brown     if (isVTK) {
31440a96aa3bSJed Brown       next = next->next;
31450a96aa3bSJed Brown       continue;
31460a96aa3bSJed Brown     }
31479566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "_forest_base_subpoint_map", &isSpmap));
31480a96aa3bSJed Brown     if (!isSpmap) {
31499566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(base, name, &baseLabel));
31500a96aa3bSJed Brown       if (!baseLabel) {
31510a96aa3bSJed Brown         next = next->next;
31520a96aa3bSJed Brown         continue;
31530a96aa3bSJed Brown       }
31549566063dSJacob Faibussowitsch       PetscCall(DMLabelCreateIndex(baseLabel, pStartBase, pEndBase));
31550a96aa3bSJed Brown     } else baseLabel = NULL;
31560a96aa3bSJed Brown 
31570a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
31580a96aa3bSJed Brown       PetscInt          s, c = -1, l;
31590a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
31600a96aa3bSJed Brown       p4est_quadrant_t *ghosts  = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
31610a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t *)pforest->forest->trees->array;
31620a96aa3bSJed Brown       p4est_quadrant_t *q;
31630a96aa3bSJed Brown       PetscInt          t, val;
31640a96aa3bSJed Brown       PetscBool         zerosupportpoint = PETSC_FALSE;
31650a96aa3bSJed Brown 
31669566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
31670a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
31680a96aa3bSJed Brown         PetscInt point = star[2 * s];
31690a96aa3bSJed Brown 
31700a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
31719566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(plex, point, PETSC_TRUE, &closureSize, &closure));
31720a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
31730a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
31740a96aa3bSJed Brown             do { /* check parents of q */
31750a96aa3bSJed Brown               q = qParent;
31760a96aa3bSJed Brown               if (q == p) {
31770a96aa3bSJed Brown                 c = point;
31780a96aa3bSJed Brown                 break;
31790a96aa3bSJed Brown               }
31809566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex, q, &qParent, NULL));
31810a96aa3bSJed Brown             } while (qParent != q);
31820a96aa3bSJed Brown             if (c != -1) break;
31839566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(plex, pp, &pParent, NULL));
31840a96aa3bSJed Brown             q = closure[2 * l];
31850a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
31860a96aa3bSJed Brown               pp = pParent;
31870a96aa3bSJed Brown               if (pp == q) {
31880a96aa3bSJed Brown                 c = point;
31890a96aa3bSJed Brown                 break;
31900a96aa3bSJed Brown               }
31919566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex, pp, &pParent, NULL));
31920a96aa3bSJed Brown             }
31930a96aa3bSJed Brown             if (c != -1) break;
31940a96aa3bSJed Brown           }
31959566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(plex, point, PETSC_TRUE, NULL, &closure));
31960a96aa3bSJed Brown           if (l < closureSize) break;
31970a96aa3bSJed Brown         } else {
31980a96aa3bSJed Brown           PetscInt supportSize;
31990a96aa3bSJed Brown 
32009566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(plex, point, &supportSize));
32010a96aa3bSJed Brown           zerosupportpoint = (PetscBool)(zerosupportpoint || !supportSize);
32020a96aa3bSJed Brown         }
32030a96aa3bSJed Brown       }
32040a96aa3bSJed Brown       if (c < 0) {
32050a96aa3bSJed Brown         const char *prefix;
32060a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
32070a96aa3bSJed Brown 
32089566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
32099566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, prefix, "-dm_forest_print_label_error", &print, NULL));
32100a96aa3bSJed Brown         if (print) {
32110a96aa3bSJed Brown           PetscInt i;
32120a96aa3bSJed Brown 
321363a3b9bcSJacob 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));
321463a3b9bcSJacob 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]));
32150a96aa3bSJed Brown         }
32169566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, NULL, &star));
32170a96aa3bSJed Brown         if (zerosupportpoint) continue;
32189371c9d4SSatish Balay         else
32199371c9d4SSatish 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");
32200a96aa3bSJed Brown       }
32219566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, NULL, &star));
32220a96aa3bSJed Brown 
32230a96aa3bSJed Brown       if (c < cLocalStart) {
32240a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
32250a96aa3bSJed Brown         q = &(ghosts[c]);
32260a96aa3bSJed Brown         t = (PetscInt)q->p.which_tree;
32270a96aa3bSJed Brown       } else if (c < cLocalEnd) {
32280a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
32290a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
32300a96aa3bSJed Brown 
32310a96aa3bSJed Brown         c -= cLocalStart;
32320a96aa3bSJed Brown 
32330a96aa3bSJed Brown         do {
32340a96aa3bSJed Brown           p4est_tree_t *tree;
32350a96aa3bSJed Brown 
32361dca8a05SBarry Smith           PetscCheck(guess >= lo && guess < num_trees && lo < hi, PETSC_COMM_SELF, PETSC_ERR_PLIB, "failed binary search");
32370a96aa3bSJed Brown           tree = &trees[guess];
32380a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
32390a96aa3bSJed Brown             hi = guess;
32400a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt)tree->quadrants.elem_count) {
32410a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt)tree->quadrants_offset];
32420a96aa3bSJed Brown             t = guess;
32430a96aa3bSJed Brown             break;
32440a96aa3bSJed Brown           } else {
32450a96aa3bSJed Brown             lo = guess + 1;
32460a96aa3bSJed Brown           }
32470a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
32480a96aa3bSJed Brown         } while (1);
32490a96aa3bSJed Brown       } else {
32500a96aa3bSJed Brown         /* get from the end of the ghost layer */
32510a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
32520a96aa3bSJed Brown 
32530a96aa3bSJed Brown         q = &(ghosts[c]);
32540a96aa3bSJed Brown         t = (PetscInt)q->p.which_tree;
32550a96aa3bSJed Brown       }
32560a96aa3bSJed Brown 
32570a96aa3bSJed Brown       if (l == 0) { /* cell */
32580a96aa3bSJed Brown         if (baseLabel) {
32599566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32600a96aa3bSJed Brown         } else {
32610a96aa3bSJed Brown           val = t + cStartBase;
32620a96aa3bSJed Brown         }
32639566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label, p, val));
32640a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
32650a96aa3bSJed Brown         p4est_quadrant_t nq;
32660a96aa3bSJed Brown         int              isInside;
32670a96aa3bSJed Brown 
32680a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
3269792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_face_neighbor, (q, l, &nq));
3270792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
32710a96aa3bSJed Brown         if (isInside) {
32720a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
32730a96aa3bSJed Brown           if (baseLabel) {
32749566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32750a96aa3bSJed Brown           } else {
32760a96aa3bSJed Brown             val = t + cStartBase;
32770a96aa3bSJed Brown           }
32789566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32790a96aa3bSJed Brown         } else {
32800a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
32810a96aa3bSJed Brown 
32820a96aa3bSJed Brown           if (baseLabel) {
32839566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
32840a96aa3bSJed Brown           } else {
32850a96aa3bSJed Brown             val = f + fStartBase;
32860a96aa3bSJed Brown           }
32879566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32880a96aa3bSJed Brown         }
32890a96aa3bSJed Brown   #if defined(P4_TO_P8)
32900a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
32910a96aa3bSJed Brown         p4est_quadrant_t nq;
32920a96aa3bSJed Brown         int              isInside;
32930a96aa3bSJed Brown 
32940a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
3295792fecdfSBarry Smith         PetscCallP4est(p8est_quadrant_edge_neighbor, (q, l, &nq));
3296792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
32970a96aa3bSJed Brown         if (isInside) {
32980a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
32990a96aa3bSJed Brown           if (baseLabel) {
33009566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
33010a96aa3bSJed Brown           } else {
33020a96aa3bSJed Brown             val = t + cStartBase;
33030a96aa3bSJed Brown           }
33049566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
33050a96aa3bSJed Brown         } else {
33060a96aa3bSJed Brown           int isOutsideFace;
33070a96aa3bSJed Brown 
3308792fecdfSBarry Smith           PetscCallP4estReturn(isOutsideFace, p4est_quadrant_is_outside_face, (&nq));
33090a96aa3bSJed Brown           if (isOutsideFace) {
33100a96aa3bSJed Brown             PetscInt f;
33110a96aa3bSJed Brown 
33120a96aa3bSJed Brown             if (nq.x < 0) {
33130a96aa3bSJed Brown               f = 0;
33140a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33150a96aa3bSJed Brown               f = 1;
33160a96aa3bSJed Brown             } else if (nq.y < 0) {
33170a96aa3bSJed Brown               f = 2;
33180a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33190a96aa3bSJed Brown               f = 3;
33200a96aa3bSJed Brown             } else if (nq.z < 0) {
33210a96aa3bSJed Brown               f = 4;
33220a96aa3bSJed Brown             } else {
33230a96aa3bSJed Brown               f = 5;
33240a96aa3bSJed Brown             }
33250a96aa3bSJed Brown             f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33260a96aa3bSJed Brown             if (baseLabel) {
33279566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
33280a96aa3bSJed Brown             } else {
33290a96aa3bSJed Brown               val = f + fStartBase;
33300a96aa3bSJed Brown             }
33319566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33320a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
33330a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
33340a96aa3bSJed Brown 
33350a96aa3bSJed Brown             if (baseLabel) {
33369566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, e + eStartBase, &val));
33370a96aa3bSJed Brown             } else {
33380a96aa3bSJed Brown               val = e + eStartBase;
33390a96aa3bSJed Brown             }
33409566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33410a96aa3bSJed Brown           }
33420a96aa3bSJed Brown         }
33430a96aa3bSJed Brown   #endif
33440a96aa3bSJed Brown       } else { /* vertex */
33450a96aa3bSJed Brown         p4est_quadrant_t nq;
33460a96aa3bSJed Brown         int              isInside;
33470a96aa3bSJed Brown 
33480a96aa3bSJed Brown   #if defined(P4_TO_P8)
33490a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
33500a96aa3bSJed Brown   #else
33510a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
33520a96aa3bSJed Brown   #endif
3353792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_corner_neighbor, (q, l, &nq));
3354792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
33550a96aa3bSJed Brown         if (isInside) {
33560a96aa3bSJed Brown           if (baseLabel) {
33579566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
33580a96aa3bSJed Brown           } else {
33590a96aa3bSJed Brown             val = t + cStartBase;
33600a96aa3bSJed Brown           }
33619566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
33620a96aa3bSJed Brown         } else {
33630a96aa3bSJed Brown           int isOutside;
33640a96aa3bSJed Brown 
3365792fecdfSBarry Smith           PetscCallP4estReturn(isOutside, p4est_quadrant_is_outside_face, (&nq));
33660a96aa3bSJed Brown           if (isOutside) {
33670a96aa3bSJed Brown             PetscInt f = -1;
33680a96aa3bSJed Brown 
33690a96aa3bSJed Brown             if (nq.x < 0) {
33700a96aa3bSJed Brown               f = 0;
33710a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33720a96aa3bSJed Brown               f = 1;
33730a96aa3bSJed Brown             } else if (nq.y < 0) {
33740a96aa3bSJed Brown               f = 2;
33750a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33760a96aa3bSJed Brown               f = 3;
33770a96aa3bSJed Brown   #if defined(P4_TO_P8)
33780a96aa3bSJed Brown             } else if (nq.z < 0) {
33790a96aa3bSJed Brown               f = 4;
33800a96aa3bSJed Brown             } else {
33810a96aa3bSJed Brown               f = 5;
33820a96aa3bSJed Brown   #endif
33830a96aa3bSJed Brown             }
33840a96aa3bSJed Brown             f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33850a96aa3bSJed Brown             if (baseLabel) {
33869566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
33870a96aa3bSJed Brown             } else {
33880a96aa3bSJed Brown               val = f + fStartBase;
33890a96aa3bSJed Brown             }
33909566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33910a96aa3bSJed Brown             continue;
33920a96aa3bSJed Brown           }
33930a96aa3bSJed Brown   #if defined(P4_TO_P8)
3394792fecdfSBarry Smith           PetscCallP4estReturn(isOutside, p8est_quadrant_is_outside_edge, (&nq));
33950a96aa3bSJed Brown           if (isOutside) {
33960a96aa3bSJed Brown             /* outside edge */
33970a96aa3bSJed Brown             PetscInt e = -1;
33980a96aa3bSJed Brown 
33990a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
34000a96aa3bSJed Brown               if (nq.z < 0) {
34010a96aa3bSJed Brown                 if (nq.y < 0) {
34020a96aa3bSJed Brown                   e = 0;
34030a96aa3bSJed Brown                 } else {
34040a96aa3bSJed Brown                   e = 1;
34050a96aa3bSJed Brown                 }
34060a96aa3bSJed Brown               } else {
34070a96aa3bSJed Brown                 if (nq.y < 0) {
34080a96aa3bSJed Brown                   e = 2;
34090a96aa3bSJed Brown                 } else {
34100a96aa3bSJed Brown                   e = 3;
34110a96aa3bSJed Brown                 }
34120a96aa3bSJed Brown               }
34130a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
34140a96aa3bSJed Brown               if (nq.z < 0) {
34150a96aa3bSJed Brown                 if (nq.x < 0) {
34160a96aa3bSJed Brown                   e = 4;
34170a96aa3bSJed Brown                 } else {
34180a96aa3bSJed Brown                   e = 5;
34190a96aa3bSJed Brown                 }
34200a96aa3bSJed Brown               } else {
34210a96aa3bSJed Brown                 if (nq.x < 0) {
34220a96aa3bSJed Brown                   e = 6;
34230a96aa3bSJed Brown                 } else {
34240a96aa3bSJed Brown                   e = 7;
34250a96aa3bSJed Brown                 }
34260a96aa3bSJed Brown               }
34270a96aa3bSJed Brown             } else {
34280a96aa3bSJed Brown               if (nq.y < 0) {
34290a96aa3bSJed Brown                 if (nq.x < 0) {
34300a96aa3bSJed Brown                   e = 8;
34310a96aa3bSJed Brown                 } else {
34320a96aa3bSJed Brown                   e = 9;
34330a96aa3bSJed Brown                 }
34340a96aa3bSJed Brown               } else {
34350a96aa3bSJed Brown                 if (nq.x < 0) {
34360a96aa3bSJed Brown                   e = 10;
34370a96aa3bSJed Brown                 } else {
34380a96aa3bSJed Brown                   e = 11;
34390a96aa3bSJed Brown                 }
34400a96aa3bSJed Brown               }
34410a96aa3bSJed Brown             }
34420a96aa3bSJed Brown 
34430a96aa3bSJed Brown             e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
34440a96aa3bSJed Brown             if (baseLabel) {
34459566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, e + eStartBase, &val));
34460a96aa3bSJed Brown             } else {
34470a96aa3bSJed Brown               val = e + eStartBase;
34480a96aa3bSJed Brown             }
34499566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
34500a96aa3bSJed Brown             continue;
34510a96aa3bSJed Brown           }
34520a96aa3bSJed Brown   #endif
34530a96aa3bSJed Brown           {
34540a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
34550a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
34560a96aa3bSJed Brown 
34570a96aa3bSJed Brown             if (baseLabel) {
34589566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, v + vStartBase, &val));
34590a96aa3bSJed Brown             } else {
34600a96aa3bSJed Brown               val = v + vStartBase;
34610a96aa3bSJed Brown             }
34629566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
34630a96aa3bSJed Brown           }
34640a96aa3bSJed Brown         }
34650a96aa3bSJed Brown       }
34660a96aa3bSJed Brown     }
34670a96aa3bSJed Brown     next = next->next;
34680a96aa3bSJed Brown   }
34693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34700a96aa3bSJed Brown }
34710a96aa3bSJed Brown 
3472d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex)
3473d71ae5a4SJacob Faibussowitsch {
34740a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
34750a96aa3bSJed Brown   DM                 adapt;
34760a96aa3bSJed Brown 
34770a96aa3bSJed Brown   PetscFunctionBegin;
34783ba16761SJacob Faibussowitsch   if (pforest->labelsFinalized) PetscFunctionReturn(PETSC_SUCCESS);
34790a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
34809566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
34810a96aa3bSJed Brown   if (!adapt) {
34820a96aa3bSJed Brown     /* Initialize labels from the base dm */
34839566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsInitialize(dm, plex));
34840a96aa3bSJed Brown   } else {
34850a96aa3bSJed Brown     PetscInt    dofPerDim[4] = {1, 1, 1, 1};
34860a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
34870a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
34880a96aa3bSJed Brown     PetscInt   *values, *adaptValues;
34890a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
34900a96aa3bSJed Brown     DMLabel     adaptLabel;
34910a96aa3bSJed Brown     DM          adaptPlex;
34920a96aa3bSJed Brown 
34939566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm, &adaptLabel));
34949566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(adapt, &adaptPlex));
34959566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF(adapt, dm, dofPerDim, &transferForward, &transferBackward));
34969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &pStart, &pEnd));
34979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(adaptPlex, &pStartA, &pEndA));
34989566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEnd - pStart, &values, pEndA - pStartA, &adaptValues));
34999566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex, &pointSF));
35000a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
35010a96aa3bSJed Brown       PetscInt p;
35020a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p - pStartA] = -1;
35030a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p - pStart] = -2;
35040a96aa3bSJed Brown       if (transferForward) {
35059566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
35069566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
35070a96aa3bSJed Brown       }
35080a96aa3bSJed Brown       if (transferBackward) {
350957168dbeSPierre Jolivet         PetscCall(PetscSFReduceBegin(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
351057168dbeSPierre Jolivet         PetscCall(PetscSFReduceEnd(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35110a96aa3bSJed Brown       }
35120a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35130a96aa3bSJed Brown         PetscInt q = p, parent;
35140a96aa3bSJed Brown 
35159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35160a96aa3bSJed Brown         while (parent != q) {
35170a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
35180a96aa3bSJed Brown           q = parent;
35199566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35200a96aa3bSJed Brown         }
35210a96aa3bSJed Brown       }
352257168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, values, values, MPI_MAX));
352357168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, values, values, MPI_MAX));
35249566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35259566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, values, values, MPI_REPLACE));
3526ad540459SPierre Jolivet       for (p = pStart; p < pEnd; p++) PetscCheck(values[p - pStart] != -2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "uncovered point %" PetscInt_FMT, p);
35270a96aa3bSJed Brown     }
35280a96aa3bSJed Brown     while (next) {
35290a96aa3bSJed Brown       DMLabel     nextLabel = next->label;
35300a96aa3bSJed Brown       const char *name;
35310a96aa3bSJed Brown       PetscBool   isDepth, isCellType, isGhost, isVTK;
35320a96aa3bSJed Brown       DMLabel     label;
35330a96aa3bSJed Brown       PetscInt    p;
35340a96aa3bSJed Brown 
35359566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)nextLabel, &name));
35369566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isDepth));
35370a96aa3bSJed Brown       if (isDepth) {
35380a96aa3bSJed Brown         next = next->next;
35390a96aa3bSJed Brown         continue;
35400a96aa3bSJed Brown       }
35419566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "celltype", &isCellType));
35420a96aa3bSJed Brown       if (isCellType) {
35430a96aa3bSJed Brown         next = next->next;
35440a96aa3bSJed Brown         continue;
35450a96aa3bSJed Brown       }
35469566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "ghost", &isGhost));
35470a96aa3bSJed Brown       if (isGhost) {
35480a96aa3bSJed Brown         next = next->next;
35490a96aa3bSJed Brown         continue;
35500a96aa3bSJed Brown       }
35519566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "vtk", &isVTK));
35520a96aa3bSJed Brown       if (isVTK) {
35530a96aa3bSJed Brown         next = next->next;
35540a96aa3bSJed Brown         continue;
35550a96aa3bSJed Brown       }
35560a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
35570a96aa3bSJed Brown         next = next->next;
35580a96aa3bSJed Brown         continue;
35590a96aa3bSJed Brown       }
35600a96aa3bSJed Brown       /* label was created earlier */
35619566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
356248a46eb9SPierre Jolivet       for (p = pStartA; p < pEndA; p++) PetscCall(DMLabelGetValue(nextLabel, p, &adaptValues[p]));
35630a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
35640a96aa3bSJed Brown 
35651baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastBegin(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
356657168dbeSPierre Jolivet       if (transferBackward) PetscCall(PetscSFReduceBegin(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35671baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastEnd(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
356857168dbeSPierre Jolivet       if (transferBackward) PetscCall(PetscSFReduceEnd(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35690a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35700a96aa3bSJed Brown         PetscInt q = p, parent;
35710a96aa3bSJed Brown 
35729566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35730a96aa3bSJed Brown         while (parent != q) {
35740a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
35750a96aa3bSJed Brown           q = parent;
35769566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35770a96aa3bSJed Brown         }
35780a96aa3bSJed Brown       }
357957168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, values, values, MPI_MAX));
358057168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, values, values, MPI_MAX));
35819566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35829566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35830a96aa3bSJed Brown 
358448a46eb9SPierre Jolivet       for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(label, p, values[p]));
35850a96aa3bSJed Brown       next = next->next;
35860a96aa3bSJed Brown     }
35879566063dSJacob Faibussowitsch     PetscCall(PetscFree2(values, adaptValues));
35889566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferForward));
35899566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferBackward));
35900a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
35910a96aa3bSJed Brown   }
35923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35930a96aa3bSJed Brown }
35940a96aa3bSJed Brown 
3595d71ae5a4SJacob Faibussowitsch 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)
3596d71ae5a4SJacob Faibussowitsch {
35970a96aa3bSJed Brown   PetscInt     closureSize, c, coordStart, coordEnd, coordDim;
35980a96aa3bSJed Brown   PetscInt    *closure = NULL;
35990a96aa3bSJed Brown   PetscSection coordSec;
36000a96aa3bSJed Brown 
36010a96aa3bSJed Brown   PetscFunctionBegin;
36029566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &coordSec));
36039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSec, &coordStart, &coordEnd));
36049566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(plex, &coordDim));
36059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(plex, cell, PETSC_TRUE, &closureSize, &closure));
36060a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
36070a96aa3bSJed Brown     PetscInt point = closure[2 * c];
36080a96aa3bSJed Brown 
36090a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
36100a96aa3bSJed Brown       PetscInt dof, off;
36110a96aa3bSJed Brown       PetscInt nCoords, i;
36129566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec, point, &dof));
361308401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not understand coordinate layout");
36140a96aa3bSJed Brown       nCoords = dof / coordDim;
36159566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec, point, &off));
36160a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
36170a96aa3bSJed Brown         PetscScalar *coord               = &coords[off + i * coordDim];
36180a96aa3bSJed Brown         double       coordP4est[3]       = {0.};
36190a96aa3bSJed Brown         double       coordP4estMapped[3] = {0.};
36200a96aa3bSJed Brown         PetscInt     j;
36210a96aa3bSJed Brown         PetscReal    treeCoords[P4EST_CHILDREN][3] = {{0.}};
36220a96aa3bSJed Brown         PetscReal    eta[3]                        = {0.};
36230a96aa3bSJed Brown         PetscInt     numRounds                     = 10;
36240a96aa3bSJed Brown         PetscReal    coordGuess[3]                 = {0.};
36250a96aa3bSJed Brown 
36260a96aa3bSJed Brown         eta[0] = (PetscReal)q->x / (PetscReal)P4EST_ROOT_LEN;
36270a96aa3bSJed Brown         eta[1] = (PetscReal)q->y / (PetscReal)P4EST_ROOT_LEN;
36280a96aa3bSJed Brown   #if defined(P4_TO_P8)
36290a96aa3bSJed Brown         eta[2] = (PetscReal)q->z / (PetscReal)P4EST_ROOT_LEN;
36300a96aa3bSJed Brown   #endif
36310a96aa3bSJed Brown 
36320a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
36330a96aa3bSJed Brown           PetscInt k;
36340a96aa3bSJed Brown 
36350a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
36360a96aa3bSJed Brown         }
36370a96aa3bSJed Brown 
36380a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
36390a96aa3bSJed Brown           PetscInt  k;
36400a96aa3bSJed Brown           PetscReal prod = 1.;
36410a96aa3bSJed Brown 
36420a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
36430a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
36440a96aa3bSJed Brown         }
36450a96aa3bSJed Brown 
36460a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
36470a96aa3bSJed Brown           PetscInt dir;
36480a96aa3bSJed Brown 
36490a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
36500a96aa3bSJed Brown             PetscInt  k;
36510a96aa3bSJed Brown             PetscReal diff[3];
36520a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
36530a96aa3bSJed Brown             PetscReal rhs, scale, update;
36540a96aa3bSJed Brown 
36550a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
36560a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
36570a96aa3bSJed Brown               PetscInt  l;
36580a96aa3bSJed Brown               PetscReal prod = 1.;
36590a96aa3bSJed Brown 
36600a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
36610a96aa3bSJed Brown                 if (l == dir) {
36620a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? 1. : -1.;
36630a96aa3bSJed Brown                 } else {
36640a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
36650a96aa3bSJed Brown                 }
36660a96aa3bSJed Brown               }
36670a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
36680a96aa3bSJed Brown             }
36690a96aa3bSJed Brown             rhs   = 0.;
36700a96aa3bSJed Brown             scale = 0;
36710a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
36720a96aa3bSJed Brown               rhs += diff[k] * dXdeta[k];
36730a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
36740a96aa3bSJed Brown             }
36750a96aa3bSJed Brown             update = rhs / scale;
36760a96aa3bSJed Brown             eta[dir] += update;
36770a96aa3bSJed Brown             eta[dir] = PetscMin(eta[dir], 1.);
36780a96aa3bSJed Brown             eta[dir] = PetscMax(eta[dir], 0.);
36790a96aa3bSJed Brown 
36800a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
36810a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
36820a96aa3bSJed Brown               PetscInt  l;
36830a96aa3bSJed Brown               PetscReal prod = 1.;
36840a96aa3bSJed Brown 
36850a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
36860a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
36870a96aa3bSJed Brown             }
36880a96aa3bSJed Brown           }
36890a96aa3bSJed Brown         }
36900a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double)eta[j];
36910a96aa3bSJed Brown 
36920a96aa3bSJed Brown         if (geom) {
36930a96aa3bSJed Brown           (geom->X)(geom, t, coordP4est, coordP4estMapped);
36940a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar)coordP4estMapped[j];
36950a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not coded");
36960a96aa3bSJed Brown       }
36970a96aa3bSJed Brown     }
36980a96aa3bSJed Brown   }
36999566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(plex, cell, PETSC_TRUE, &closureSize, &closure));
37003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37010a96aa3bSJed Brown }
37020a96aa3bSJed Brown 
3703d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex)
3704d71ae5a4SJacob Faibussowitsch {
37050a96aa3bSJed Brown   DM_Forest         *forest;
37060a96aa3bSJed Brown   DM_Forest_pforest *pforest;
37070a96aa3bSJed Brown   p4est_geometry_t  *geom;
37080a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd;
37090a96aa3bSJed Brown   Vec                coordLocalVec;
37100a96aa3bSJed Brown   PetscScalar       *coords;
37110a96aa3bSJed Brown   p4est_topidx_t     flt, llt, t;
37120a96aa3bSJed Brown   p4est_tree_t      *trees;
37130a96aa3bSJed Brown   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
37140a96aa3bSJed Brown   void *mapCtx;
37150a96aa3bSJed Brown 
37160a96aa3bSJed Brown   PetscFunctionBegin;
37170a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
37180a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
37190a96aa3bSJed Brown   geom    = pforest->topo->geom;
37209566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
37213ba16761SJacob Faibussowitsch   if (!geom && !map) PetscFunctionReturn(PETSC_SUCCESS);
37229566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex, &coordLocalVec));
37239566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordLocalVec, &coords));
37240a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
37250a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
37260a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
37270a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
37280a96aa3bSJed Brown   trees       = (p4est_tree_t *)pforest->forest->trees->array;
37290a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
37300a96aa3bSJed Brown     PetscSection coordSec;
37310a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
37320a96aa3bSJed Brown     DM           base;
37330a96aa3bSJed Brown 
37349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
37352827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
37360a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
37379566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm, &base));
37389566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(plex, &coordSec));
37399566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(coordSec, &coordStart, &coordEnd));
37409566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(plex, &coordDim));
37410a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim, 3);
37420a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
37430a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
37440a96aa3bSJed Brown       PetscInt  dof, off, cell = -1, coarsePoint = -1;
37450a96aa3bSJed Brown       PetscInt  nCoords, i;
37469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec, p, &dof));
374708401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not understand coordinate layout");
37480a96aa3bSJed Brown       nCoords = dof / coordDim;
37499566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec, p, &off));
37509566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
37510a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
37520a96aa3bSJed Brown         PetscInt point = star[2 * i];
37530a96aa3bSJed Brown 
37540a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
37550a96aa3bSJed Brown           cell = point;
37560a96aa3bSJed Brown           break;
37570a96aa3bSJed Brown         }
37580a96aa3bSJed Brown       }
37599566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
37600a96aa3bSJed Brown       if (cell >= 0) {
37610a96aa3bSJed Brown         if (cell < cLocalStart) {
37620a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37630a96aa3bSJed Brown 
37640a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
37650a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
37660a96aa3bSJed Brown           cell -= cLocalStart;
37670a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
37680a96aa3bSJed Brown             p4est_tree_t *tree = &(trees[t]);
37690a96aa3bSJed Brown 
37700a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t)cell < tree->quadrants_offset + tree->quadrants.elem_count) {
37710a96aa3bSJed Brown               coarsePoint = t;
37720a96aa3bSJed Brown               break;
37730a96aa3bSJed Brown             }
37740a96aa3bSJed Brown           }
37750a96aa3bSJed Brown         } else {
37760a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37770a96aa3bSJed Brown 
37780a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
37790a96aa3bSJed Brown         }
37800a96aa3bSJed Brown       }
37810a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
37820a96aa3bSJed Brown         PetscScalar *coord               = &coords[off + i * coordDim];
37830a96aa3bSJed Brown         PetscReal    coordP4est[3]       = {0.};
37840a96aa3bSJed Brown         PetscReal    coordP4estMapped[3] = {0.};
37850a96aa3bSJed Brown         PetscInt     j;
37860a96aa3bSJed Brown 
37870a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
37889566063dSJacob Faibussowitsch         PetscCall((map)(base, coarsePoint, p4estCoordDim, coordP4est, coordP4estMapped, mapCtx));
37890a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar)coordP4estMapped[j];
37900a96aa3bSJed Brown       }
37910a96aa3bSJed Brown     }
37920a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
37930a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
37940a96aa3bSJed Brown 
37959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
37962827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
37970a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
37980a96aa3bSJed Brown     if (cLocalStart > 0) {
37990a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
38000a96aa3bSJed Brown       PetscInt          count;
38010a96aa3bSJed Brown 
38020a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
38030a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
38040a96aa3bSJed Brown         p4est_topidx_t    t    = quad->p.which_tree;
38050a96aa3bSJed Brown 
38069566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count, quad, t, pforest->topo->conn, coords));
38070a96aa3bSJed Brown       }
38080a96aa3bSJed Brown     }
38090a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
38100a96aa3bSJed Brown       p4est_tree_t     *tree     = &(trees[t]);
38110a96aa3bSJed Brown       PetscInt          offset   = cLocalStart + tree->quadrants_offset, i;
38120a96aa3bSJed Brown       PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
38130a96aa3bSJed Brown       p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
38140a96aa3bSJed Brown 
38150a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
38160a96aa3bSJed Brown         PetscInt count = i + offset;
38170a96aa3bSJed Brown 
38189566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count, &quads[i], t, pforest->topo->conn, coords));
38190a96aa3bSJed Brown       }
38200a96aa3bSJed Brown     }
38210a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
38220a96aa3bSJed Brown       p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
38230a96aa3bSJed Brown       PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
38240a96aa3bSJed Brown       PetscInt          count;
38250a96aa3bSJed Brown 
38260a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
38270a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
38280a96aa3bSJed Brown         p4est_topidx_t    t    = quad->p.which_tree;
38290a96aa3bSJed Brown 
38309566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count + cLocalEnd, quad, t, pforest->topo->conn, coords));
38310a96aa3bSJed Brown       }
38320a96aa3bSJed Brown     }
38330a96aa3bSJed Brown   }
38349566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordLocalVec, &coords));
38353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38360a96aa3bSJed Brown }
38370a96aa3bSJed Brown 
3838d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestQuadrantIsInterior(p4est_quadrant_t *quad, PetscBool *is_interior)
3839d71ae5a4SJacob Faibussowitsch {
3840852b71a7SToby Isaac   PetscFunctionBegin;
3841852b71a7SToby Isaac   p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3842852b71a7SToby Isaac   if ((quad->x > 0) && (quad->x + h < P4EST_ROOT_LEN)
3843852b71a7SToby Isaac   #ifdef P4_TO_P8
3844852b71a7SToby Isaac       && (quad->z > 0) && (quad->z + h < P4EST_ROOT_LEN)
3845852b71a7SToby Isaac   #endif
3846852b71a7SToby Isaac       && (quad->y > 0) && (quad->y + h < P4EST_ROOT_LEN)) {
3847852b71a7SToby Isaac     *is_interior = PETSC_TRUE;
3848852b71a7SToby Isaac   } else {
3849852b71a7SToby Isaac     *is_interior = PETSC_FALSE;
3850852b71a7SToby Isaac   }
38513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3852852b71a7SToby Isaac }
3853852b71a7SToby Isaac 
3854852b71a7SToby Isaac /* We always use DG coordinates with p4est: if they do not match the vertex
3855852b71a7SToby Isaac    coordinates, add space for them in the section */
3856d71ae5a4SJacob Faibussowitsch 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)
3857d71ae5a4SJacob Faibussowitsch {
3858852b71a7SToby Isaac   PetscBool is_interior;
3859852b71a7SToby Isaac 
3860852b71a7SToby Isaac   PetscFunctionBegin;
3861852b71a7SToby Isaac   PetscCall(PforestQuadrantIsInterior(quad, &is_interior));
3862852b71a7SToby Isaac   if (is_interior) { // quads in the interior of a coarse cell can't touch periodic interfaces
3863852b71a7SToby Isaac     PetscCall(PetscSectionSetDof(newSection, cell, 0));
3864852b71a7SToby Isaac     PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3865852b71a7SToby Isaac   } else {
3866852b71a7SToby Isaac     PetscInt     cSize;
3867852b71a7SToby Isaac     PetscScalar *values      = NULL;
3868852b71a7SToby Isaac     PetscBool    same_coords = PETSC_TRUE;
3869852b71a7SToby Isaac 
3870852b71a7SToby Isaac     PetscCall(DMPlexVecGetClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3871852b71a7SToby Isaac     PetscAssert(cSize == cDim * P4EST_CHILDREN, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected closure size");
3872852b71a7SToby Isaac     for (int c = 0; c < P4EST_CHILDREN; c++) {
3873852b71a7SToby Isaac       p4est_qcoord_t quad_coords[3];
3874852b71a7SToby Isaac       p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3875852b71a7SToby Isaac       double         corner_coords[3];
3876852b71a7SToby Isaac       double         vert_coords[3];
3877852b71a7SToby Isaac       PetscInt       corner = PetscVertToP4estVert[c];
3878852b71a7SToby Isaac 
3879ad540459SPierre Jolivet       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) vert_coords[d] = PetscRealPart(values[c * cDim + d]);
3880852b71a7SToby Isaac 
3881852b71a7SToby Isaac       quad_coords[0] = quad->x;
3882852b71a7SToby Isaac       quad_coords[1] = quad->y;
3883852b71a7SToby Isaac   #ifdef P4_TO_P8
3884852b71a7SToby Isaac       quad_coords[2] = quad->z;
3885852b71a7SToby Isaac   #endif
3886ad540459SPierre Jolivet       for (int d = 0; d < 3; d++) quad_coords[d] += (corner & (1 << d)) ? h : 0;
3887852b71a7SToby Isaac   #ifndef P4_TO_P8
3888648bc8c4SBarry Smith       PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3889852b71a7SToby Isaac   #else
3890648bc8c4SBarry Smith       PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3891852b71a7SToby Isaac   #endif
3892852b71a7SToby Isaac       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
3893852b71a7SToby Isaac         if (fabs(vert_coords[d] - corner_coords[d]) > PETSC_SMALL) {
3894852b71a7SToby Isaac           same_coords = PETSC_FALSE;
3895852b71a7SToby Isaac           break;
3896852b71a7SToby Isaac         }
3897852b71a7SToby Isaac       }
3898852b71a7SToby Isaac     }
3899852b71a7SToby Isaac     if (same_coords) {
3900852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, 0));
3901852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3902852b71a7SToby Isaac     } else {
3903852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, cSize));
3904852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, cSize));
3905852b71a7SToby Isaac     }
3906852b71a7SToby Isaac     PetscCall(DMPlexVecRestoreClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3907852b71a7SToby Isaac   }
39083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3909852b71a7SToby Isaac }
3910852b71a7SToby Isaac 
3911d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestLocalizeCell(DM plex, PetscInt cDim, DM_Forest_pforest *pforest, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad, PetscScalar coords[])
3912d71ae5a4SJacob Faibussowitsch {
3913852b71a7SToby Isaac   PetscInt cdof, off;
3914852b71a7SToby Isaac 
3915852b71a7SToby Isaac   PetscFunctionBegin;
3916852b71a7SToby Isaac   PetscCall(PetscSectionGetDof(newSection, cell, &cdof));
39173ba16761SJacob Faibussowitsch   if (!cdof) PetscFunctionReturn(PETSC_SUCCESS);
3918852b71a7SToby Isaac 
3919852b71a7SToby Isaac   PetscCall(PetscSectionGetOffset(newSection, cell, &off));
3920852b71a7SToby Isaac   for (PetscInt c = 0, pos = off; c < P4EST_CHILDREN; c++) {
3921852b71a7SToby Isaac     p4est_qcoord_t quad_coords[3];
3922852b71a7SToby Isaac     p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3923852b71a7SToby Isaac     double         corner_coords[3];
3924852b71a7SToby Isaac     PetscInt       corner = PetscVertToP4estVert[c];
3925852b71a7SToby Isaac 
3926852b71a7SToby Isaac     quad_coords[0] = quad->x;
3927852b71a7SToby Isaac     quad_coords[1] = quad->y;
3928852b71a7SToby Isaac   #ifdef P4_TO_P8
3929852b71a7SToby Isaac     quad_coords[2] = quad->z;
3930852b71a7SToby Isaac   #endif
3931ad540459SPierre Jolivet     for (int d = 0; d < 3; d++) quad_coords[d] += (corner & (1 << d)) ? h : 0;
3932852b71a7SToby Isaac   #ifndef P4_TO_P8
3933648bc8c4SBarry Smith     PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3934852b71a7SToby Isaac   #else
3935648bc8c4SBarry Smith     PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3936852b71a7SToby Isaac   #endif
3937ad540459SPierre Jolivet     for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) coords[pos++] = corner_coords[d];
3938ad540459SPierre Jolivet     for (PetscInt d = PetscMin(cDim, 3); d < cDim; d++) coords[pos++] = 0.;
3939852b71a7SToby Isaac   }
39403ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3941852b71a7SToby Isaac }
3942852b71a7SToby Isaac 
3943d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
3944d71ae5a4SJacob Faibussowitsch {
39450a96aa3bSJed Brown   DM_Forest         *forest;
39460a96aa3bSJed Brown   DM_Forest_pforest *pforest;
39476858538eSMatthew G. Knepley   DM                 base, cdm, cdmCell;
3948852b71a7SToby Isaac   Vec                cVec, cVecOld;
3949852b71a7SToby Isaac   PetscSection       oldSection, newSection;
39500a96aa3bSJed Brown   PetscScalar       *coords2;
39516858538eSMatthew G. Knepley   const PetscReal   *L;
39520a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd, coarsePoint;
3953852b71a7SToby Isaac   PetscInt           cDim, newStart, newEnd;
3954852b71a7SToby Isaac   PetscInt           v, vStart, vEnd, cp, cStart, cEnd, cEndInterior;
39550a96aa3bSJed Brown   p4est_topidx_t     flt, llt, t;
39560a96aa3bSJed Brown   p4est_tree_t      *trees;
39576858538eSMatthew G. Knepley   PetscBool          baseLocalized = PETSC_FALSE;
39580a96aa3bSJed Brown 
39590a96aa3bSJed Brown   PetscFunctionBegin;
39604fb89dddSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dm, NULL, NULL, &L));
39610a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
39629566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cDim));
39639566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
39646858538eSMatthew G. Knepley   if (base) PetscCall(DMGetCoordinatesLocalized(base, &baseLocalized));
39650a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
39663ba16761SJacob Faibussowitsch   if (!baseLocalized && !L) PetscFunctionReturn(PETSC_SUCCESS);
39679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &newStart, &newEnd));
39680a96aa3bSJed Brown 
39699566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newSection));
39709566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(newSection, 1));
39719566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim));
39729566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSection, newStart, newEnd));
39730a96aa3bSJed Brown 
39749566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &oldSection));
39759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
3976852b71a7SToby Isaac   PetscCall(DMGetCoordinatesLocal(plex, &cVecOld));
39770a96aa3bSJed Brown 
39780a96aa3bSJed Brown   forest      = (DM_Forest *)dm->data;
39790a96aa3bSJed Brown   pforest     = (DM_Forest_pforest *)forest->data;
39800a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
39810a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
39820a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
39830a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
39840a96aa3bSJed Brown   trees       = (p4est_tree_t *)pforest->forest->trees->array;
39850a96aa3bSJed Brown 
39869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
39872827ebadSStefano Zampini   PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
39880a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
3989852b71a7SToby Isaac   cp   = 0;
39900a96aa3bSJed Brown   if (cLocalStart > 0) {
39910a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
3992852b71a7SToby Isaac     PetscInt          cell;
39930a96aa3bSJed Brown 
3994852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
3995852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
3996852b71a7SToby Isaac 
39970a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
3998852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
39990a96aa3bSJed Brown     }
40000a96aa3bSJed Brown   }
40010a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
40020a96aa3bSJed Brown     p4est_tree_t     *tree     = &(trees[t]);
40030a96aa3bSJed Brown     PetscInt          offset   = cLocalStart + tree->quadrants_offset;
40040a96aa3bSJed Brown     PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
4005852b71a7SToby Isaac     p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
40060a96aa3bSJed Brown     PetscInt          i;
40070a96aa3bSJed Brown 
40080a96aa3bSJed Brown     if (!numQuads) continue;
40090a96aa3bSJed Brown     coarsePoint = t;
4010852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4011852b71a7SToby Isaac       PetscInt          cell = i + offset;
4012852b71a7SToby Isaac       p4est_quadrant_t *quad = &quads[i];
40130a96aa3bSJed Brown 
4014852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
40150a96aa3bSJed Brown     }
40160a96aa3bSJed Brown   }
40170a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
40180a96aa3bSJed Brown     p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
40190a96aa3bSJed Brown     PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
40200a96aa3bSJed Brown     PetscInt          count;
40210a96aa3bSJed Brown 
4022852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
40230a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
40240a96aa3bSJed Brown       coarsePoint            = quad->p.which_tree;
4025852b71a7SToby Isaac       PetscInt cell          = count + cLocalEnd;
40260a96aa3bSJed Brown 
4027852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
40280a96aa3bSJed Brown     }
40290a96aa3bSJed Brown   }
4030852b71a7SToby Isaac   PetscAssert(cp == cEnd - cStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT, cp, cEnd - cStart);
40310a96aa3bSJed Brown 
40329566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSection));
40336858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(plex, &cdm));
40346858538eSMatthew G. Knepley   PetscCall(DMClone(cdm, &cdmCell));
40356858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(plex, cdmCell));
40366858538eSMatthew G. Knepley   PetscCall(DMDestroy(&cdmCell));
40376858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateSection(plex, cDim, newSection));
40389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &v));
40399566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
40409566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)cVec, "coordinates"));
40419566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(cVec, cDim));
40429566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE));
40439566063dSJacob Faibussowitsch   PetscCall(VecSetType(cVec, VECSTANDARD));
40449566063dSJacob Faibussowitsch   PetscCall(VecSet(cVec, PETSC_MIN_REAL));
40450a96aa3bSJed Brown 
40460a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
40476858538eSMatthew G. Knepley   PetscCall(VecGetArray(cVec, &coords2));
4048852b71a7SToby Isaac   cp = 0;
4049852b71a7SToby Isaac   if (cLocalStart > 0) {
4050852b71a7SToby Isaac     p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
4051852b71a7SToby Isaac     PetscInt          cell;
4052852b71a7SToby Isaac 
4053852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
4054852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
4055852b71a7SToby Isaac 
4056852b71a7SToby Isaac       coarsePoint = quad->p.which_tree;
4057852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4058852b71a7SToby Isaac     }
4059852b71a7SToby Isaac   }
40600a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
40610a96aa3bSJed Brown     p4est_tree_t     *tree     = &(trees[t]);
40620a96aa3bSJed Brown     PetscInt          offset   = cLocalStart + tree->quadrants_offset;
40630a96aa3bSJed Brown     PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
4064852b71a7SToby Isaac     p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
4065852b71a7SToby Isaac     PetscInt          i;
40660a96aa3bSJed Brown 
40670a96aa3bSJed Brown     if (!numQuads) continue;
4068852b71a7SToby Isaac     coarsePoint = t;
4069852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4070852b71a7SToby Isaac       PetscInt          cell = i + offset;
40710a96aa3bSJed Brown       p4est_quadrant_t *quad = &quads[i];
40720a96aa3bSJed Brown 
4073852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4074852b71a7SToby Isaac     }
4075852b71a7SToby Isaac   }
4076852b71a7SToby Isaac   if (cLocalEnd - cLocalStart < cEnd - cStart) {
4077852b71a7SToby Isaac     p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
4078852b71a7SToby Isaac     PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
4079852b71a7SToby Isaac     PetscInt          count;
40800a96aa3bSJed Brown 
4081852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
4082852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
4083852b71a7SToby Isaac       coarsePoint            = quad->p.which_tree;
4084852b71a7SToby Isaac       PetscInt cell          = count + cLocalEnd;
40850a96aa3bSJed Brown 
4086852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
40870a96aa3bSJed Brown     }
40880a96aa3bSJed Brown   }
40899566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cVec, &coords2));
40906858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(plex, cVec));
40919566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cVec));
40929566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&newSection));
40933ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40940a96aa3bSJed Brown }
40950a96aa3bSJed Brown 
40960a96aa3bSJed Brown   #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
4097d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
4098d71ae5a4SJacob Faibussowitsch {
40990a96aa3bSJed Brown   DM_Forest         *forest;
41000a96aa3bSJed Brown   DM_Forest_pforest *pforest;
41010a96aa3bSJed Brown 
41020a96aa3bSJed Brown   PetscFunctionBegin;
41030a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
41040a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
41059566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointAdaptToSelfSF)));
41069566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointSelfToAdaptSF)));
41079566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
41089566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
41093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41100a96aa3bSJed Brown }
41110a96aa3bSJed Brown 
4112d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
4113d71ae5a4SJacob Faibussowitsch {
41140a96aa3bSJed Brown   DM_Forest           *forest;
41150a96aa3bSJed Brown   DM_Forest_pforest   *pforest;
41160a96aa3bSJed Brown   DM                   refTree, newPlex, base;
41170a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
41180a96aa3bSJed Brown   MPI_Comm             comm;
41190a96aa3bSJed Brown   PetscBool            isPforest;
41200a96aa3bSJed Brown   PetscInt             dim;
41210a96aa3bSJed Brown   PetscInt             overlap;
41220a96aa3bSJed Brown   p4est_connect_type_t ctype;
41230a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
41240a96aa3bSJed Brown   sc_array_t          *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
41250a96aa3bSJed Brown   PetscSection         parentSection;
41260a96aa3bSJed Brown   PetscSF              pointSF;
41270a96aa3bSJed Brown   size_t               zz, count;
41280a96aa3bSJed Brown   PetscInt             pStart, pEnd;
41290a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
41300a96aa3bSJed Brown 
41310a96aa3bSJed Brown   PetscFunctionBegin;
41320a96aa3bSJed Brown 
41330a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41340a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
41359566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPFOREST, &isPforest));
413628b400f6SJacob Faibussowitsch   PetscCheck(isPforest, comm, PETSC_ERR_ARG_WRONG, "Expected DM type %s, got %s", DMPFOREST, ((PetscObject)dm)->type_name);
41379566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
413863a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Expected DM dimension %d, got %" PetscInt_FMT, P4EST_DIM, dim);
41390a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
41400a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
41419566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
414248a46eb9SPierre Jolivet   if (base) PetscCall(DMGetLabel(base, "ghost", &ghostLabelBase));
41430a96aa3bSJed Brown   if (!pforest->plex) {
41440a96aa3bSJed Brown     PetscMPIInt size;
41450a96aa3bSJed Brown 
41469566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
41479566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm, &newPlex));
41489566063dSJacob Faibussowitsch     PetscCall(DMSetType(newPlex, DMPLEX));
41499566063dSJacob Faibussowitsch     PetscCall(DMSetMatType(newPlex, dm->mattype));
41500a96aa3bSJed Brown     /* share labels */
41519566063dSJacob Faibussowitsch     PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
41529566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
41539566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
41549566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
41550a96aa3bSJed Brown     if (adjDim == 0) {
41560a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
41570a96aa3bSJed Brown     } else if (adjCodim == 1) {
41580a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
41590a96aa3bSJed Brown   #if defined(P4_TO_P8)
41600a96aa3bSJed Brown     } else if (adjDim == 1) {
41610a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
41620a96aa3bSJed Brown   #endif
41630a96aa3bSJed Brown     } else {
416463a3b9bcSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid adjacency dimension %" PetscInt_FMT, adjDim);
41650a96aa3bSJed Brown     }
416663a3b9bcSJacob 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);
41679566063dSJacob Faibussowitsch     PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
416860667520SVaclav Hapla     PetscCall(DMPlexSetOverlap_Plex(newPlex, NULL, overlap));
41690a96aa3bSJed Brown 
41700a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
41710a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
41720a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
41730a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
41740a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
41750a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
41760a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
41770a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
41780a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
41790a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
41800a96aa3bSJed Brown 
4181792fecdfSBarry 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));
41820a96aa3bSJed Brown 
41830a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt)first_local_quad;
41840a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt)pforest->forest->local_num_quadrants;
41859566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
41869566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
41879566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
41889566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
41899566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, coordDim));
41909566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(children));
41919566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(parents));
41929566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(childids));
41939566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(leaves));
41949566063dSJacob Faibussowitsch     PetscCall(locidx_pair_to_PetscSFNode(remotes));
41950a96aa3bSJed Brown 
41969566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(newPlex, P4EST_DIM));
41979566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDim(newPlex, coordDim));
41989566063dSJacob Faibussowitsch     PetscCall(DMPlexSetMaxProjectionHeight(newPlex, P4EST_DIM - 1));
41999566063dSJacob 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));
42009566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(newPlex));
42019566063dSJacob Faibussowitsch     PetscCall(DMCreateReferenceTree_pforest(comm, &refTree));
42029566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(newPlex, refTree));
42039566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(comm, &parentSection));
42049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(newPlex, &pStart, &pEnd));
42059566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
42060a96aa3bSJed Brown     count = children->elem_count;
42070a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
42080a96aa3bSJed Brown       PetscInt child = *((PetscInt *)sc_array_index(children, zz));
42090a96aa3bSJed Brown 
42109566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(parentSection, child, 1));
42110a96aa3bSJed Brown     }
42129566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
42139566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(newPlex, parentSection, (PetscInt *)parents->array, (PetscInt *)childids->array));
42149566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&parentSection));
42159566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &pointSF));
42160a96aa3bSJed Brown     /*
42170a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
42180a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
42190a96aa3bSJed Brown     */
42209566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(pointSF, pEnd - pStart, (PetscInt)leaves->elem_count, (PetscInt *)leaves->array, PETSC_COPY_VALUES, (PetscSFNode *)remotes->array, PETSC_COPY_VALUES));
42219566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(newPlex, pointSF));
42229566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(dm, pointSF));
42230a96aa3bSJed Brown     {
42240a96aa3bSJed Brown       DM coordDM;
42250a96aa3bSJed Brown 
42269566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex, &coordDM));
42279566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(coordDM, pointSF));
42280a96aa3bSJed Brown     }
42299566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointSF));
42300a96aa3bSJed Brown     sc_array_destroy(points_per_dim);
42310a96aa3bSJed Brown     sc_array_destroy(cone_sizes);
42320a96aa3bSJed Brown     sc_array_destroy(cones);
42330a96aa3bSJed Brown     sc_array_destroy(cone_orientations);
42340a96aa3bSJed Brown     sc_array_destroy(coords);
42350a96aa3bSJed Brown     sc_array_destroy(children);
42360a96aa3bSJed Brown     sc_array_destroy(parents);
42370a96aa3bSJed Brown     sc_array_destroy(childids);
42380a96aa3bSJed Brown     sc_array_destroy(leaves);
42390a96aa3bSJed Brown     sc_array_destroy(remotes);
42400a96aa3bSJed Brown 
42410a96aa3bSJed Brown     {
42424fb89dddSMatthew G. Knepley       const PetscReal *maxCell, *Lstart, *L;
42430a96aa3bSJed Brown 
42444fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
42454fb89dddSMatthew G. Knepley       PetscCall(DMSetPeriodicity(newPlex, maxCell, Lstart, L));
42469566063dSJacob Faibussowitsch       PetscCall(DMPforestLocalizeCoordinates(dm, newPlex));
42470a96aa3bSJed Brown     }
42480a96aa3bSJed Brown 
42490a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
42500a96aa3bSJed Brown       Vec                coordsGlobal, coordsLocal;
42510a96aa3bSJed Brown       const PetscScalar *globalArray;
42520a96aa3bSJed Brown       PetscScalar       *localArray;
42530a96aa3bSJed Brown       PetscSF            coordSF;
42540a96aa3bSJed Brown       DM                 coordDM;
42550a96aa3bSJed Brown 
42569566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex, &coordDM));
42579566063dSJacob Faibussowitsch       PetscCall(DMGetSectionSF(coordDM, &coordSF));
42589566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinates(newPlex, &coordsGlobal));
42599566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal));
42609566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordsGlobal, &globalArray));
42619566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordsLocal, &localArray));
42629566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coordSF, MPIU_SCALAR, globalArray, localArray, MPI_REPLACE));
42639566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coordSF, MPIU_SCALAR, globalArray, localArray, MPI_REPLACE));
42649566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordsLocal, &localArray));
42659566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray));
42669566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal));
42670a96aa3bSJed Brown     }
42689566063dSJacob Faibussowitsch     PetscCall(DMPforestMapCoordinates(dm, newPlex));
42690a96aa3bSJed Brown 
42700a96aa3bSJed Brown     pforest->plex = newPlex;
42710a96aa3bSJed Brown 
42720a96aa3bSJed Brown     /* copy labels */
42739566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsFinalize(dm, newPlex));
42740a96aa3bSJed Brown 
42750a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
42760a96aa3bSJed Brown       PetscInt numAdded;
42770a96aa3bSJed Brown       DM       newPlexGhosted;
42780a96aa3bSJed Brown       void    *ctx;
42790a96aa3bSJed Brown 
42809566063dSJacob Faibussowitsch       PetscCall(DMPlexConstructGhostCells(newPlex, pforest->ghostName, &numAdded, &newPlexGhosted));
42819566063dSJacob Faibussowitsch       PetscCall(DMGetApplicationContext(newPlex, &ctx));
42829566063dSJacob Faibussowitsch       PetscCall(DMSetApplicationContext(newPlexGhosted, ctx));
42830a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
42849566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(newPlexGhosted, &pointSF));
42859566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(dm, pointSF));
42869566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&newPlex));
42879566063dSJacob Faibussowitsch       PetscCall(DMPlexSetReferenceTree(newPlexGhosted, refTree));
42889566063dSJacob Faibussowitsch       PetscCall(DMForestClearAdaptivityForest_pforest(dm));
42890a96aa3bSJed Brown       newPlex = newPlexGhosted;
42900a96aa3bSJed Brown 
42910a96aa3bSJed Brown       /* share the labels back */
42929566063dSJacob Faibussowitsch       PetscCall(DMDestroyLabelLinkList_Internal(dm));
42939566063dSJacob Faibussowitsch       PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
42940a96aa3bSJed Brown       pforest->plex = newPlex;
42950a96aa3bSJed Brown     }
42969566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&refTree));
42970a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
4298d0609cedSBarry Smith       PetscObjectOptionsBegin((PetscObject)newPlex);
4299dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(newPlex, PetscOptionsObject));
4300dbbe0bcdSBarry Smith       PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)newPlex, PetscOptionsObject));
4301d0609cedSBarry Smith       PetscOptionsEnd();
43020a96aa3bSJed Brown     }
43039566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(newPlex, NULL, "-dm_p4est_plex_view"));
43040a96aa3bSJed Brown     {
43056858538eSMatthew G. Knepley       DM           cdm;
43060a96aa3bSJed Brown       PetscSection coordsSec;
43070a96aa3bSJed Brown       Vec          coords;
43080a96aa3bSJed Brown       PetscInt     cDim;
43090a96aa3bSJed Brown 
43109566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(newPlex, &cDim));
43119566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(newPlex, &coordsSec));
43129566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinateSection(dm, cDim, coordsSec));
43139566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coords));
43149566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(dm, coords));
43156858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateDM(newPlex, &cdm));
43166858538eSMatthew G. Knepley       if (cdm) PetscCall(DMSetCellCoordinateDM(dm, cdm));
43176858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateSection(newPlex, &coordsSec));
43186858538eSMatthew G. Knepley       if (coordsSec) PetscCall(DMSetCellCoordinateSection(dm, cDim, coordsSec));
43196858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinatesLocal(newPlex, &coords));
43206858538eSMatthew G. Knepley       if (coords) PetscCall(DMSetCellCoordinatesLocal(dm, coords));
43210a96aa3bSJed Brown     }
43220a96aa3bSJed Brown   }
43230a96aa3bSJed Brown   newPlex = pforest->plex;
43240a96aa3bSJed Brown   if (plex) {
43259566063dSJacob Faibussowitsch     PetscCall(DMClone(newPlex, plex));
43266858538eSMatthew G. Knepley   #if 0
43279566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43289566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDM(*plex,coordDM));
43296858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(newPlex,&coordDM));
43306858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*plex,coordDM));
43316858538eSMatthew G. Knepley   #endif
43329566063dSJacob Faibussowitsch     PetscCall(DMShareDiscretization(dm, *plex));
43330a96aa3bSJed Brown   }
43343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43350a96aa3bSJed Brown }
43360a96aa3bSJed Brown 
4337d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSetFromOptions_pforest(DM dm, PetscOptionItems *PetscOptionsObject)
4338d71ae5a4SJacob Faibussowitsch {
43390a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43400a96aa3bSJed Brown   char               stringBuffer[256];
43410a96aa3bSJed Brown   PetscBool          flg;
43420a96aa3bSJed Brown 
43430a96aa3bSJed Brown   PetscFunctionBegin;
4344dbbe0bcdSBarry Smith   PetscCall(DMSetFromOptions_Forest(dm, PetscOptionsObject));
4345d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DM" P4EST_STRING " options");
43469566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening", "partition forest to allow for coarsening", "DMP4estSetPartitionForCoarsening", pforest->partition_for_coarsening, &(pforest->partition_for_coarsening), NULL));
43479566063dSJacob 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));
4348d0609cedSBarry Smith   PetscOptionsHeadEnd();
43490a96aa3bSJed Brown   if (flg) {
43509566063dSJacob Faibussowitsch     PetscCall(PetscFree(pforest->ghostName));
43519566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(stringBuffer, &pforest->ghostName));
43520a96aa3bSJed Brown   }
43533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43540a96aa3bSJed Brown }
43550a96aa3bSJed Brown 
43560a96aa3bSJed Brown   #if !defined(P4_TO_P8)
43570a96aa3bSJed Brown     #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
43580a96aa3bSJed Brown     #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
43590a96aa3bSJed Brown   #else
43600a96aa3bSJed Brown     #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
43610a96aa3bSJed Brown     #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
43620a96aa3bSJed Brown   #endif
43630a96aa3bSJed Brown 
4364d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
4365d71ae5a4SJacob Faibussowitsch {
43660a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43670a96aa3bSJed Brown 
43680a96aa3bSJed Brown   PetscFunctionBegin;
43690a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43700a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43710a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
43723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43730a96aa3bSJed Brown }
43740a96aa3bSJed Brown 
4375d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
4376d71ae5a4SJacob Faibussowitsch {
43770a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43780a96aa3bSJed Brown 
43790a96aa3bSJed Brown   PetscFunctionBegin;
43800a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43810a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43820a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
43833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43840a96aa3bSJed Brown }
43850a96aa3bSJed Brown 
4386d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetPlex(DM dm, DM *plex)
4387d71ae5a4SJacob Faibussowitsch {
43880a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43890a96aa3bSJed Brown 
43900a96aa3bSJed Brown   PetscFunctionBegin;
43910a96aa3bSJed Brown   if (plex) *plex = NULL;
43929566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
43930a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
439448a46eb9SPierre Jolivet   if (!pforest->plex) PetscCall(DMConvert_pforest_plex(dm, DMPLEX, NULL));
43959566063dSJacob Faibussowitsch   PetscCall(DMShareDiscretization(dm, pforest->plex));
43960a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
43973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43980a96aa3bSJed Brown }
43990a96aa3bSJed Brown 
44000a96aa3bSJed Brown   #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
4401d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
4402d71ae5a4SJacob Faibussowitsch {
44030a96aa3bSJed Brown   PetscSection gsc, gsf;
44040a96aa3bSJed Brown   PetscInt     m, n;
44050a96aa3bSJed Brown   DM           cdm;
44060a96aa3bSJed Brown 
44070a96aa3bSJed Brown   PetscFunctionBegin;
44089566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
44099566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
44109566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
44119566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
44120a96aa3bSJed Brown 
44139566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmFine), interpolation));
44149566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
44159566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, MATAIJ));
44160a96aa3bSJed Brown 
44179566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
441808401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse, PetscObjectComm((PetscObject)dmFine), PETSC_ERR_SUP, "Only interpolation from coarse DM for now");
44190a96aa3bSJed Brown 
44200a96aa3bSJed Brown   {
44210a96aa3bSJed Brown     DM        plexF, plexC;
44220a96aa3bSJed Brown     PetscSF   sf;
44230a96aa3bSJed Brown     PetscInt *cids;
44240a96aa3bSJed Brown     PetscInt  dofPerDim[4] = {1, 1, 1, 1};
44250a96aa3bSJed Brown 
44269566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse, &plexC));
44279566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine, &plexF));
44289566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
44299566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
44309566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
44319566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
44329566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
44330a96aa3bSJed Brown   }
44349566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
44350a96aa3bSJed Brown   /* Use naive scaling */
44369566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
44373ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44380a96aa3bSJed Brown }
44390a96aa3bSJed Brown 
44400a96aa3bSJed Brown   #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
4441d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
4442d71ae5a4SJacob Faibussowitsch {
44430a96aa3bSJed Brown   PetscSection gsc, gsf;
44440a96aa3bSJed Brown   PetscInt     m, n;
44450a96aa3bSJed Brown   DM           cdm;
44460a96aa3bSJed Brown 
44470a96aa3bSJed Brown   PetscFunctionBegin;
44489566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
44499566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n));
44509566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
44519566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m));
44520a96aa3bSJed Brown 
44539566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmFine), injection));
44549566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
44559566063dSJacob Faibussowitsch   PetscCall(MatSetType(*injection, MATAIJ));
44560a96aa3bSJed Brown 
44579566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
445808401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse, PetscObjectComm((PetscObject)dmFine), PETSC_ERR_SUP, "Only injection to coarse DM for now");
44590a96aa3bSJed Brown 
44600a96aa3bSJed Brown   {
44610a96aa3bSJed Brown     DM        plexF, plexC;
44620a96aa3bSJed Brown     PetscSF   sf;
44630a96aa3bSJed Brown     PetscInt *cids;
44640a96aa3bSJed Brown     PetscInt  dofPerDim[4] = {1, 1, 1, 1};
44650a96aa3bSJed Brown 
44669566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse, &plexC));
44679566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine, &plexF));
44689566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
44699566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
44709566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
44719566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
44729566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
44730a96aa3bSJed Brown   }
44749566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
44750a96aa3bSJed Brown   /* Use naive scaling */
44763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44770a96aa3bSJed Brown }
44780a96aa3bSJed Brown 
44790a96aa3bSJed Brown   #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
4480d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
4481d71ae5a4SJacob Faibussowitsch {
44820a96aa3bSJed Brown   DM        dmIn, dmVecIn, base, basec, plex, coarseDM;
44830a96aa3bSJed Brown   DM       *hierarchy;
44840a96aa3bSJed Brown   PetscSF   sfRed = NULL;
44850a96aa3bSJed Brown   PetscDS   ds;
44860a96aa3bSJed Brown   Vec       vecInLocal, vecOutLocal;
44870a96aa3bSJed Brown   DMLabel   subpointMap;
44880a96aa3bSJed Brown   PetscInt  minLevel, mh, n_hi, i;
44890a96aa3bSJed Brown   PetscBool hiforest, *hierarchy_forest;
44900a96aa3bSJed Brown 
44910a96aa3bSJed Brown   PetscFunctionBegin;
44929566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vecIn, &dmVecIn));
44939566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmVecIn, &ds));
449428b400f6SJacob Faibussowitsch   PetscCheck(ds, PetscObjectComm((PetscObject)dmVecIn), PETSC_ERR_SUP, "Cannot transfer without a PetscDS object");
44950a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
44960a96aa3bSJed Brown     PetscSection section;
44970a96aa3bSJed Brown     PetscInt     Nf;
44980a96aa3bSJed Brown 
44999566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn, &section));
45009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
450163a3b9bcSJacob 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);
45020a96aa3bSJed Brown   }
45039566063dSJacob Faibussowitsch   PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
450463a3b9bcSJacob Faibussowitsch   PetscCheck(!minLevel, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)", minLevel);
45059566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
450628b400f6SJacob Faibussowitsch   PetscCheck(base, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing base DM");
45070a96aa3bSJed Brown 
45089566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
45090a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
45109566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45110a96aa3bSJed Brown   } else {
45120a96aa3bSJed Brown     PetscSection secIn, secInRed;
45130a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
45140a96aa3bSJed Brown 
45159566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)base, "_base_migration_sf", (PetscObject *)&sfRed));
451628b400f6SJacob Faibussowitsch     PetscCheck(sfRed, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not the DM set with DMForestSetBaseDM()");
45179566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn), &secInRed));
45189566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF, &vecInRed));
45199566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn, &secIn));
45209566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmVecIn, &vecInLocal));
45219566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmVecIn, vecIn, INSERT_VALUES, vecInLocal));
45229566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmVecIn, vecIn, INSERT_VALUES, vecInLocal));
45239566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeField(dmVecIn, sfRed, secIn, vecInLocal, secInRed, vecInRed));
45249566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmVecIn, &vecInLocal));
45259566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secInRed));
45260a96aa3bSJed Brown     vecIn = vecInRed;
45270a96aa3bSJed Brown   }
45280a96aa3bSJed Brown 
45290a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
45300a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
45310a96aa3bSJed Brown   hiforest = PETSC_TRUE;
45320a96aa3bSJed Brown 
45330a96aa3bSJed Brown   /* upsweep to the coarsest DM */
45340a96aa3bSJed Brown   n_hi     = 0;
45350a96aa3bSJed Brown   coarseDM = dm;
45360a96aa3bSJed Brown   do {
45370a96aa3bSJed Brown     PetscBool isforest;
45380a96aa3bSJed Brown 
45390a96aa3bSJed Brown     dmIn = coarseDM;
45400a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
45419566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dmIn));
45429566063dSJacob Faibussowitsch     PetscCall(DMIsForest(dmIn, &isforest));
454328b400f6SJacob Faibussowitsch     PetscCheck(isforest, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "Cannot currently transfer through a mixed hierarchy! Found DM type %s", ((PetscObject)dmIn)->type_name);
45440a96aa3bSJed Brown     coarseDM = NULL;
454548a46eb9SPierre Jolivet     if (hiforest) PetscCall(DMForestGetAdaptivityForest(dmIn, &coarseDM));
45460a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
45470a96aa3bSJed Brown       hiforest = PETSC_FALSE;
45489566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn, &coarseDM));
45490a96aa3bSJed Brown     }
45500a96aa3bSJed Brown     n_hi++;
45510a96aa3bSJed Brown   } while (coarseDM);
45520a96aa3bSJed Brown 
45539566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n_hi, &hierarchy, n_hi, &hierarchy_forest));
45540a96aa3bSJed Brown 
45550a96aa3bSJed Brown   i        = 0;
45560a96aa3bSJed Brown   hiforest = PETSC_TRUE;
45570a96aa3bSJed Brown   coarseDM = dm;
45580a96aa3bSJed Brown   do {
45590a96aa3bSJed Brown     dmIn     = coarseDM;
45600a96aa3bSJed Brown     coarseDM = NULL;
456148a46eb9SPierre Jolivet     if (hiforest) PetscCall(DMForestGetAdaptivityForest(dmIn, &coarseDM));
45620a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
45630a96aa3bSJed Brown       hiforest = PETSC_FALSE;
45649566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn, &coarseDM));
45650a96aa3bSJed Brown     }
45660a96aa3bSJed Brown     i++;
45670a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
45680a96aa3bSJed Brown   } while (coarseDM);
45690a96aa3bSJed Brown 
45700a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
45719566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn, &plex));
45720a96aa3bSJed Brown 
45730a96aa3bSJed Brown   /* Check this plex is compatible with the base */
45740a96aa3bSJed Brown   {
45750a96aa3bSJed Brown     IS       gnum[2];
45760a96aa3bSJed Brown     PetscInt ncells[2], gncells[2];
45770a96aa3bSJed Brown 
45789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(base, &gnum[0]));
45799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(plex, &gnum[1]));
45809566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[0], NULL, &ncells[0]));
45819566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[1], NULL, &ncells[1]));
45821c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(ncells, gncells, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
458363a3b9bcSJacob 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);
45840a96aa3bSJed Brown   }
45850a96aa3bSJed Brown 
45869566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dmIn, "_forest_base_subpoint_map", &subpointMap));
458728b400f6SJacob Faibussowitsch   PetscCheck(subpointMap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing _forest_base_subpoint_map label");
45880a96aa3bSJed Brown 
45899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(base, &mh));
45909566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(plex, mh));
45910a96aa3bSJed Brown 
45929566063dSJacob Faibussowitsch   PetscCall(DMClone(base, &basec));
45939566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmVecIn, basec));
45940a96aa3bSJed Brown   if (sfRed) {
45959566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45960a96aa3bSJed Brown     vecInLocal = vecIn;
45970a96aa3bSJed Brown   } else {
45989566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(basec, &vecInLocal));
45999566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(basec, vecIn, INSERT_VALUES, vecInLocal));
46009566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(basec, vecIn, INSERT_VALUES, vecInLocal));
46010a96aa3bSJed Brown   }
46020a96aa3bSJed Brown 
46039566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmIn, &vecOutLocal));
46040a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
46050a96aa3bSJed Brown     PetscSF            basetocoarse;
46060a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
46070a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
46080a96aa3bSJed Brown     PetscMPIInt        rank;
46090a96aa3bSJed Brown     PetscSFNode       *remotes;
46100a96aa3bSJed Brown     PetscSection       secIn, secOut;
46110a96aa3bSJed Brown     PetscInt          *remoteOffsets;
46120a96aa3bSJed Brown     PetscSF            transferSF;
46130a96aa3bSJed Brown     const PetscScalar *inArray;
46140a96aa3bSJed Brown     PetscScalar       *outArray;
46150a96aa3bSJed Brown 
46169566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
46179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(basec, &bStart, &bEnd));
46180a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
46199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &iStart, &iEnd));
46200a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
46210a96aa3bSJed Brown 
46229566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &remotes));
46230a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
46240a96aa3bSJed Brown       PetscInt index;
46250a96aa3bSJed Brown 
46260a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
46279566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(subpointMap, leaf, &index));
46280a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
46290a96aa3bSJed Brown     }
46300a96aa3bSJed Brown 
46319566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
46329566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
46339566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(basetocoarse));
46349566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(basec, &secIn));
46359566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn), &secOut));
46369566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
46379566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
46389566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
46399566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(vecOutLocal, &outArray));
46409566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecInLocal, &inArray));
46419566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray, MPI_REPLACE));
46429566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray, MPI_REPLACE));
46439566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecInLocal, &inArray));
46449566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray));
46459566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferSF));
46469566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secOut));
46479566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&basetocoarse));
46480a96aa3bSJed Brown   }
46499566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecInLocal));
46509566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&basec));
46519566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecIn));
46520a96aa3bSJed Brown 
46530a96aa3bSJed Brown   /* output */
46540a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
46550a96aa3bSJed Brown     Vec vecOut1, vecOut2;
46560a96aa3bSJed Brown     DM  fineDM;
46570a96aa3bSJed Brown 
46589566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmIn, &vecOut1));
46599566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn, vecOutLocal, INSERT_VALUES, vecOut1));
46609566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecOutLocal));
46610a96aa3bSJed Brown     for (i = 1; i < n_hi - 1; i++) {
46620a96aa3bSJed Brown       fineDM = hierarchy[i];
46639566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(fineDM, &vecOut2));
46649566063dSJacob Faibussowitsch       PetscCall(DMForestTransferVec(dmIn, vecOut1, fineDM, vecOut2, PETSC_TRUE, 0.0));
46659566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmIn, &vecOut1));
46660a96aa3bSJed Brown       vecOut1 = vecOut2;
46670a96aa3bSJed Brown       dmIn    = fineDM;
46680a96aa3bSJed Brown     }
46699566063dSJacob Faibussowitsch     PetscCall(DMForestTransferVec(dmIn, vecOut1, dm, vecOut, PETSC_TRUE, 0.0));
46709566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmIn, &vecOut1));
46710a96aa3bSJed Brown   } else {
46729566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn, vecOutLocal, INSERT_VALUES, vecOut));
46739566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecOutLocal));
46740a96aa3bSJed Brown   }
46759566063dSJacob Faibussowitsch   PetscCall(PetscFree2(hierarchy, hierarchy_forest));
46763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46770a96aa3bSJed Brown }
46780a96aa3bSJed Brown 
46790a96aa3bSJed Brown   #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
4680d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
4681d71ae5a4SJacob Faibussowitsch {
46820a96aa3bSJed Brown   DM          adaptIn, adaptOut, plexIn, plexOut;
46830a96aa3bSJed Brown   DM_Forest  *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
46840a96aa3bSJed Brown   PetscInt    dofPerDim[] = {1, 1, 1, 1};
46850a96aa3bSJed Brown   PetscSF     inSF = NULL, outSF = NULL;
46860a96aa3bSJed Brown   PetscInt   *inCids = NULL, *outCids = NULL;
46870a96aa3bSJed Brown   DMAdaptFlag purposeIn, purposeOut;
46880a96aa3bSJed Brown 
46890a96aa3bSJed Brown   PetscFunctionBegin;
46900a96aa3bSJed Brown   forestOut = (DM_Forest *)dmOut->data;
46910a96aa3bSJed Brown   forestIn  = (DM_Forest *)dmIn->data;
46920a96aa3bSJed Brown 
46939566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmOut, &adaptOut));
46949566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmOut, &purposeOut));
46950a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *)adaptOut->data : NULL;
46960a96aa3bSJed Brown 
46979566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmIn, &adaptIn));
46989566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmIn, &purposeIn));
46990a96aa3bSJed Brown   forestAdaptIn = adaptIn ? (DM_Forest *)adaptIn->data : NULL;
47000a96aa3bSJed Brown 
47010a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
47020a96aa3bSJed Brown     switch (purposeOut) {
47030a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47049566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47059566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47060a96aa3bSJed Brown       break;
47070a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
47080a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
47099566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_TRUE, &outCids));
47109566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47110a96aa3bSJed Brown       break;
47120a96aa3bSJed Brown     default:
47139566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47149566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_FALSE, &outCids));
47159566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47169566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47170a96aa3bSJed Brown     }
47180a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
47190a96aa3bSJed Brown     switch (purposeIn) {
47200a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47219566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_TRUE, &inCids));
47229566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47230a96aa3bSJed Brown       break;
47240a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
47250a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
47269566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47279566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47280a96aa3bSJed Brown       break;
47290a96aa3bSJed Brown     default:
47309566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47319566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_FALSE, &outCids));
47329566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47339566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47340a96aa3bSJed Brown     }
47350a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "Only support transfer from pre-adaptivity to post-adaptivity right now");
47369566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn, &plexIn));
47379566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmOut, &plexOut));
47380a96aa3bSJed Brown 
47399566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferVecTree(plexIn, vecIn, plexOut, vecOut, inSF, outSF, inCids, outCids, useBCs, time));
47409566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
47419566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
47429566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&inSF));
47439566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&outSF));
47449566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
47459566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
47463ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47470a96aa3bSJed Brown }
47480a96aa3bSJed Brown 
47490a96aa3bSJed Brown   #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
4750d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm, DM *cdm)
4751d71ae5a4SJacob Faibussowitsch {
47520a96aa3bSJed Brown   DM plex;
47530a96aa3bSJed Brown 
47540a96aa3bSJed Brown   PetscFunctionBegin;
47550a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47569566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47579566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(plex, cdm));
47589566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)*cdm));
47593ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47600a96aa3bSJed Brown }
47610a96aa3bSJed Brown 
47620a96aa3bSJed Brown   #define VecViewLocal_pforest _append_pforest(VecViewLocal)
4763d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecViewLocal_pforest(Vec vec, PetscViewer viewer)
4764d71ae5a4SJacob Faibussowitsch {
47650a96aa3bSJed Brown   DM dm, plex;
47660a96aa3bSJed Brown 
47670a96aa3bSJed Brown   PetscFunctionBegin;
47689566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47699566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47709566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47719566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Local(vec, viewer));
47729566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
47733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47740a96aa3bSJed Brown }
47750a96aa3bSJed Brown 
47760a96aa3bSJed Brown   #define VecView_pforest _append_pforest(VecView)
4777d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_pforest(Vec vec, PetscViewer viewer)
4778d71ae5a4SJacob Faibussowitsch {
47790a96aa3bSJed Brown   DM dm, plex;
47800a96aa3bSJed Brown 
47810a96aa3bSJed Brown   PetscFunctionBegin;
47829566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47839566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47849566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47859566063dSJacob Faibussowitsch   PetscCall(VecView_Plex(vec, viewer));
47869566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
47873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47880a96aa3bSJed Brown }
47890a96aa3bSJed Brown 
47900a96aa3bSJed Brown   #define VecView_pforest_Native _infix_pforest(VecView, _Native)
4791d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_pforest_Native(Vec vec, PetscViewer viewer)
4792d71ae5a4SJacob Faibussowitsch {
47930a96aa3bSJed Brown   DM dm, plex;
47940a96aa3bSJed Brown 
47950a96aa3bSJed Brown   PetscFunctionBegin;
47969566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47979566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47989566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47999566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Native(vec, viewer));
48009566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
48013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48020a96aa3bSJed Brown }
48030a96aa3bSJed Brown 
48040a96aa3bSJed Brown   #define VecLoad_pforest _append_pforest(VecLoad)
4805d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecLoad_pforest(Vec vec, PetscViewer viewer)
4806d71ae5a4SJacob Faibussowitsch {
48070a96aa3bSJed Brown   DM dm, plex;
48080a96aa3bSJed Brown 
48090a96aa3bSJed Brown   PetscFunctionBegin;
48109566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
48119566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48129566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
48139566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex(vec, viewer));
48149566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
48153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48160a96aa3bSJed Brown }
48170a96aa3bSJed Brown 
48180a96aa3bSJed Brown   #define VecLoad_pforest_Native _infix_pforest(VecLoad, _Native)
4819d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecLoad_pforest_Native(Vec vec, PetscViewer viewer)
4820d71ae5a4SJacob Faibussowitsch {
48210a96aa3bSJed Brown   DM dm, plex;
48220a96aa3bSJed Brown 
48230a96aa3bSJed Brown   PetscFunctionBegin;
48249566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
48259566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48269566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
48279566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex_Native(vec, viewer));
48289566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
48293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48300a96aa3bSJed Brown }
48310a96aa3bSJed Brown 
48320a96aa3bSJed Brown   #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
4833d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateGlobalVector_pforest(DM dm, Vec *vec)
4834d71ae5a4SJacob Faibussowitsch {
48350a96aa3bSJed Brown   PetscFunctionBegin;
48369566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
48379566063dSJacob Faibussowitsch   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
48389566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
48399566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
48409566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
48419566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
48423ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48430a96aa3bSJed Brown }
48440a96aa3bSJed Brown 
48450a96aa3bSJed Brown   #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
4846d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateLocalVector_pforest(DM dm, Vec *vec)
4847d71ae5a4SJacob Faibussowitsch {
48480a96aa3bSJed Brown   PetscFunctionBegin;
48499566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
48509566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
48513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48520a96aa3bSJed Brown }
48530a96aa3bSJed Brown 
48540a96aa3bSJed Brown   #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
4855d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_pforest(DM dm, Mat *mat)
4856d71ae5a4SJacob Faibussowitsch {
48570a96aa3bSJed Brown   DM plex;
48580a96aa3bSJed Brown 
48590a96aa3bSJed Brown   PetscFunctionBegin;
48600a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48619566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48620a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only; /* maybe this should go into forest->plex */
48639566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(plex, mat));
48649566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*mat, dm));
48653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48660a96aa3bSJed Brown }
48670a96aa3bSJed Brown 
48680a96aa3bSJed Brown   #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
4869d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
4870d71ae5a4SJacob Faibussowitsch {
48710a96aa3bSJed Brown   DM plex;
48720a96aa3bSJed Brown 
48730a96aa3bSJed Brown   PetscFunctionBegin;
48740a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48759566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48769566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(plex, time, funcs, ctxs, mode, localX));
48773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48780a96aa3bSJed Brown }
48790a96aa3bSJed Brown 
48800a96aa3bSJed Brown   #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
4881d71ae5a4SJacob Faibussowitsch 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)
4882d71ae5a4SJacob Faibussowitsch {
48830a96aa3bSJed Brown   DM plex;
48840a96aa3bSJed Brown 
48850a96aa3bSJed Brown   PetscFunctionBegin;
48860a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48879566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48889566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(plex, time, label, numIds, ids, Ncc, comps, funcs, ctxs, mode, localX));
48893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48900a96aa3bSJed Brown }
48910a96aa3bSJed Brown 
48920a96aa3bSJed Brown   #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
4893d71ae5a4SJacob Faibussowitsch 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)
4894d71ae5a4SJacob Faibussowitsch {
48950a96aa3bSJed Brown   DM plex;
48960a96aa3bSJed Brown 
48970a96aa3bSJed Brown   PetscFunctionBegin;
48980a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48999566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49009566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(plex, time, localU, funcs, mode, localX));
49013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49020a96aa3bSJed Brown }
49030a96aa3bSJed Brown 
49040a96aa3bSJed Brown   #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
4905d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
4906d71ae5a4SJacob Faibussowitsch {
49070a96aa3bSJed Brown   DM plex;
49080a96aa3bSJed Brown 
49090a96aa3bSJed Brown   PetscFunctionBegin;
49100a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49119566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49129566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(plex, time, funcs, ctxs, X, diff));
49133ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49140a96aa3bSJed Brown }
49150a96aa3bSJed Brown 
49160a96aa3bSJed Brown   #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
4917d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
4918d71ae5a4SJacob Faibussowitsch {
49190a96aa3bSJed Brown   DM plex;
49200a96aa3bSJed Brown 
49210a96aa3bSJed Brown   PetscFunctionBegin;
49220a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49239566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49249566063dSJacob Faibussowitsch   PetscCall(DMComputeL2FieldDiff(plex, time, funcs, ctxs, X, diff));
49253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49260a96aa3bSJed Brown }
49270a96aa3bSJed Brown 
49280a96aa3bSJed Brown   #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
4929d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
4930d71ae5a4SJacob Faibussowitsch {
49310a96aa3bSJed Brown   DM           plex;
49320a96aa3bSJed Brown   PetscSection section;
49330a96aa3bSJed Brown 
49340a96aa3bSJed Brown   PetscFunctionBegin;
49350a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49369566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49379566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(plex, &section));
49389566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dm, section));
49393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49400a96aa3bSJed Brown }
49410a96aa3bSJed Brown 
49420a96aa3bSJed Brown   #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
4943d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
4944d71ae5a4SJacob Faibussowitsch {
49450a96aa3bSJed Brown   DM           plex;
49460a96aa3bSJed Brown   Mat          mat;
494779769bd5SJed Brown   Vec          bias;
49480a96aa3bSJed Brown   PetscSection section;
49490a96aa3bSJed Brown 
49500a96aa3bSJed Brown   PetscFunctionBegin;
49510a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49529566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49539566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(plex, &section, &mat, &bias));
49549566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, section, mat, bias));
49553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49560a96aa3bSJed Brown }
49570a96aa3bSJed Brown 
49580a96aa3bSJed Brown   #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
4959d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
4960d71ae5a4SJacob Faibussowitsch {
49610a96aa3bSJed Brown   DM plex;
49620a96aa3bSJed Brown 
49630a96aa3bSJed Brown   PetscFunctionBegin;
49640a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49659566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49669566063dSJacob Faibussowitsch   PetscCall(DMGetDimPoints(plex, dim, cStart, cEnd));
49673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49680a96aa3bSJed Brown }
49690a96aa3bSJed Brown 
49700a96aa3bSJed Brown   /* Need to forward declare */
49710a96aa3bSJed Brown   #define DMInitialize_pforest _append_pforest(DMInitialize)
49720a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
49730a96aa3bSJed Brown 
49740a96aa3bSJed Brown   #define DMClone_pforest _append_pforest(DMClone)
4975d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
4976d71ae5a4SJacob Faibussowitsch {
49770a96aa3bSJed Brown   PetscFunctionBegin;
49789566063dSJacob Faibussowitsch   PetscCall(DMClone_Forest(dm, newdm));
49799566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(*newdm));
49803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49810a96aa3bSJed Brown }
49820a96aa3bSJed Brown 
49830a96aa3bSJed Brown   #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
4984d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
4985d71ae5a4SJacob Faibussowitsch {
49860a96aa3bSJed Brown   DM_Forest         *forest;
49870a96aa3bSJed Brown   DM_Forest_pforest *pforest;
49880a96aa3bSJed Brown   PetscInt           overlap;
49890a96aa3bSJed Brown 
49900a96aa3bSJed Brown   PetscFunctionBegin;
49919566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
49920a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
49930a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
49940a96aa3bSJed Brown   *cStart = 0;
49959566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
49960a96aa3bSJed Brown   if (overlap && pforest->ghost) {
49970a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
49980a96aa3bSJed Brown   } else {
49990a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
50000a96aa3bSJed Brown   }
50013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50020a96aa3bSJed Brown }
50030a96aa3bSJed Brown 
50040a96aa3bSJed Brown   #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
5005d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
5006d71ae5a4SJacob Faibussowitsch {
50070a96aa3bSJed Brown   DM_Forest         *forest;
50080a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50090a96aa3bSJed Brown   PetscMPIInt        rank;
50100a96aa3bSJed Brown   PetscInt           overlap;
50110a96aa3bSJed Brown   PetscInt           cStart, cEnd, cLocalStart, cLocalEnd;
50120a96aa3bSJed Brown   PetscInt           nRoots, nLeaves, *mine = NULL;
50130a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
50140a96aa3bSJed Brown   PetscSF            sf;
50150a96aa3bSJed Brown 
50160a96aa3bSJed Brown   PetscFunctionBegin;
50179566063dSJacob Faibussowitsch   PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
50180a96aa3bSJed Brown   forest      = (DM_Forest *)dm->data;
50190a96aa3bSJed Brown   pforest     = (DM_Forest_pforest *)forest->data;
50200a96aa3bSJed Brown   nRoots      = cEnd - cStart;
50210a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
50220a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
50230a96aa3bSJed Brown   nLeaves     = 0;
50249566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
50259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
50260a96aa3bSJed Brown   if (overlap && pforest->ghost) {
50270a96aa3bSJed Brown     PetscSFNode      *mirror;
50280a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
50290a96aa3bSJed Brown     PetscInt          nMirror, nGhostPre, nSelf, q;
50300a96aa3bSJed Brown     void            **mirrorPtrs;
50310a96aa3bSJed Brown 
50320a96aa3bSJed Brown     nMirror   = (PetscInt)pforest->ghost->mirrors.elem_count;
50330a96aa3bSJed Brown     nSelf     = cLocalEnd - cLocalStart;
50340a96aa3bSJed Brown     nLeaves   = nRoots - nSelf;
50350a96aa3bSJed Brown     nGhostPre = (PetscInt)pforest->ghost->proc_offsets[rank];
50369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &mine));
50379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &remote));
50389566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nMirror, &mirror, nMirror, &mirrorPtrs));
50390a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t *)pforest->ghost->mirrors.array;
50400a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
50410a96aa3bSJed Brown       p4est_quadrant_t *mir = &(mirror_array[q]);
50420a96aa3bSJed Brown 
50430a96aa3bSJed Brown       mirror[q].rank  = rank;
50440a96aa3bSJed Brown       mirror[q].index = (PetscInt)mir->p.piggy3.local_num + cLocalStart;
50450a96aa3bSJed Brown       mirrorPtrs[q]   = (void *)&(mirror[q]);
50460a96aa3bSJed Brown     }
5047792fecdfSBarry Smith     PetscCallP4est(p4est_ghost_exchange_custom, (pforest->forest, pforest->ghost, sizeof(PetscSFNode), mirrorPtrs, remote));
50489566063dSJacob Faibussowitsch     PetscCall(PetscFree2(mirror, mirrorPtrs));
50490a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
50500a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
50510a96aa3bSJed Brown   }
50529566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &sf));
50539566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nRoots, nLeaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
50540a96aa3bSJed Brown   *cellSF = sf;
50553ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50560a96aa3bSJed Brown }
50570a96aa3bSJed Brown 
5058d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS *ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void *), void **setup_ctx)
5059d71ae5a4SJacob Faibussowitsch {
50600a96aa3bSJed Brown   DM plex;
50610a96aa3bSJed Brown 
50620a96aa3bSJed Brown   PetscFunctionBegin;
50639566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
50649566063dSJacob Faibussowitsch   PetscCall(DMCreateNeumannOverlap_Plex(plex, ovl, J, setup, setup_ctx));
50650a96aa3bSJed Brown   if (!*setup) {
50669566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
506748a46eb9SPierre Jolivet     if (*setup) PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
50680a96aa3bSJed Brown   }
50693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50700a96aa3bSJed Brown }
50710a96aa3bSJed Brown 
5072d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_pforest(DM dm)
5073d71ae5a4SJacob Faibussowitsch {
50740a96aa3bSJed Brown   PetscFunctionBegin;
50750a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
50760a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
50770a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
50780a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
50790a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
50800a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
50810a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
50820a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
50830a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
50840a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
50850a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
50860a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
50870a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
50880a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
50890a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
50900a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
50910a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
50920a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
50930a96aa3bSJed Brown 
50949566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_plex_pforest) "_C", DMConvert_plex_pforest));
50959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_pforest_plex) "_C", DMConvert_pforest_plex));
50969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_pforest));
50979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMForestGetPartitionOverlap));
50983ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50990a96aa3bSJed Brown }
51000a96aa3bSJed Brown 
51010a96aa3bSJed Brown   #define DMCreate_pforest _append_pforest(DMCreate)
5102d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
5103d71ae5a4SJacob Faibussowitsch {
51040a96aa3bSJed Brown   DM_Forest         *forest;
51050a96aa3bSJed Brown   DM_Forest_pforest *pforest;
51060a96aa3bSJed Brown 
51070a96aa3bSJed Brown   PetscFunctionBegin;
51089566063dSJacob Faibussowitsch   PetscCall(PetscP4estInitialize());
51099566063dSJacob Faibussowitsch   PetscCall(DMCreate_Forest(dm));
51109566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(dm));
51119566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, P4EST_DIM));
51120a96aa3bSJed Brown 
51130a96aa3bSJed Brown   /* set forest defaults */
51149566063dSJacob Faibussowitsch   PetscCall(DMForestSetTopology(dm, "unit"));
51159566063dSJacob Faibussowitsch   PetscCall(DMForestSetMinimumRefinement(dm, 0));
51169566063dSJacob Faibussowitsch   PetscCall(DMForestSetInitialRefinement(dm, 0));
51179566063dSJacob Faibussowitsch   PetscCall(DMForestSetMaximumRefinement(dm, P4EST_QMAXLEVEL));
51189566063dSJacob Faibussowitsch   PetscCall(DMForestSetGradeFactor(dm, 2));
51199566063dSJacob Faibussowitsch   PetscCall(DMForestSetAdjacencyDimension(dm, 0));
51209566063dSJacob Faibussowitsch   PetscCall(DMForestSetPartitionOverlap(dm, 0));
51210a96aa3bSJed Brown 
51220a96aa3bSJed Brown   /* create p4est data */
51234dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pforest));
51240a96aa3bSJed Brown 
51250a96aa3bSJed Brown   forest                            = (DM_Forest *)dm->data;
51260a96aa3bSJed Brown   forest->data                      = pforest;
51270a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
51280a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
51290a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
51300a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
51310a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
51320a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
51330a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
51340a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
51350a96aa3bSJed Brown   pforest->topo                     = NULL;
51360a96aa3bSJed Brown   pforest->forest                   = NULL;
51370a96aa3bSJed Brown   pforest->ghost                    = NULL;
51380a96aa3bSJed Brown   pforest->lnodes                   = NULL;
51390a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
51400a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
51410a96aa3bSJed Brown   pforest->cLocalStart              = -1;
51420a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
51430a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
51440a96aa3bSJed Brown   pforest->ghostName                = NULL;
51453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51460a96aa3bSJed Brown }
51470a96aa3bSJed Brown 
51480a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5149*3ea99036SJacob Faibussowitsch #endif
5150