xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 907a3e9c7e62a1244ef44b3544cf5c6924719401)
1a4963045SJacob Faibussowitsch #pragma once
23ea99036SJacob Faibussowitsch 
30a96aa3bSJed Brown #include <petscds.h>
40a96aa3bSJed Brown #include <petsc/private/dmimpl.h>
50a96aa3bSJed Brown #include <petsc/private/dmforestimpl.h>
60a96aa3bSJed Brown #include <petsc/private/dmpleximpl.h>
70a96aa3bSJed Brown #include <petsc/private/dmlabelimpl.h>
80a96aa3bSJed Brown #include <petsc/private/viewerimpl.h>
90a96aa3bSJed Brown #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h>
100a96aa3bSJed Brown #include "petsc_p4est_package.h"
110a96aa3bSJed Brown 
120a96aa3bSJed Brown #if defined(PETSC_HAVE_P4EST)
130a96aa3bSJed Brown 
140a96aa3bSJed Brown   #if !defined(P4_TO_P8)
150a96aa3bSJed Brown     #include <p4est.h>
160a96aa3bSJed Brown     #include <p4est_extended.h>
170a96aa3bSJed Brown     #include <p4est_geometry.h>
180a96aa3bSJed Brown     #include <p4est_ghost.h>
190a96aa3bSJed Brown     #include <p4est_lnodes.h>
200a96aa3bSJed Brown     #include <p4est_vtk.h>
210a96aa3bSJed Brown     #include <p4est_plex.h>
220a96aa3bSJed Brown     #include <p4est_bits.h>
230a96aa3bSJed Brown     #include <p4est_algorithms.h>
240a96aa3bSJed Brown   #else
250a96aa3bSJed Brown     #include <p8est.h>
260a96aa3bSJed Brown     #include <p8est_extended.h>
270a96aa3bSJed Brown     #include <p8est_geometry.h>
280a96aa3bSJed Brown     #include <p8est_ghost.h>
290a96aa3bSJed Brown     #include <p8est_lnodes.h>
300a96aa3bSJed Brown     #include <p8est_vtk.h>
310a96aa3bSJed Brown     #include <p8est_plex.h>
320a96aa3bSJed Brown     #include <p8est_bits.h>
330a96aa3bSJed Brown     #include <p8est_algorithms.h>
340a96aa3bSJed Brown   #endif
350a96aa3bSJed Brown 
369371c9d4SSatish Balay typedef enum {
379371c9d4SSatish Balay   PATTERN_HASH,
389371c9d4SSatish Balay   PATTERN_FRACTAL,
399371c9d4SSatish Balay   PATTERN_CORNER,
409371c9d4SSatish Balay   PATTERN_CENTER,
419371c9d4SSatish Balay   PATTERN_COUNT
429371c9d4SSatish Balay } DMRefinePattern;
430a96aa3bSJed Brown static const char *DMRefinePatternName[PATTERN_COUNT] = {"hash", "fractal", "corner", "center"};
440a96aa3bSJed Brown 
459371c9d4SSatish Balay typedef struct _DMRefinePatternCtx {
460a96aa3bSJed Brown   PetscInt       corner;
470a96aa3bSJed Brown   PetscBool      fractal[P4EST_CHILDREN];
480a96aa3bSJed Brown   PetscReal      hashLikelihood;
490a96aa3bSJed Brown   PetscInt       maxLevel;
500a96aa3bSJed Brown   p4est_refine_t refine_fn;
519371c9d4SSatish Balay } DMRefinePatternCtx;
520a96aa3bSJed Brown 
53d71ae5a4SJacob Faibussowitsch static int DMRefinePattern_Corner(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
54d71ae5a4SJacob Faibussowitsch {
550a96aa3bSJed Brown   p4est_quadrant_t    root, rootcorner;
560a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
570a96aa3bSJed Brown 
580a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
590a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
600a96aa3bSJed Brown 
610a96aa3bSJed Brown   root.x = root.y = 0;
620a96aa3bSJed Brown   #if defined(P4_TO_P8)
630a96aa3bSJed Brown   root.z = 0;
640a96aa3bSJed Brown   #endif
650a96aa3bSJed Brown   root.level = 0;
660a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&root, &rootcorner, ctx->corner, quadrant->level);
670a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant, &rootcorner)) return 1;
680a96aa3bSJed Brown   return 0;
690a96aa3bSJed Brown }
700a96aa3bSJed Brown 
71d71ae5a4SJacob Faibussowitsch static int DMRefinePattern_Center(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
72d71ae5a4SJacob Faibussowitsch {
730a96aa3bSJed Brown   int                 cid;
740a96aa3bSJed Brown   p4est_quadrant_t    ancestor, ancestorcorner;
750a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
760a96aa3bSJed Brown 
770a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
780a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
790a96aa3bSJed Brown   if (quadrant->level <= 1) return 1;
800a96aa3bSJed Brown 
810a96aa3bSJed Brown   p4est_quadrant_ancestor(quadrant, 1, &ancestor);
820a96aa3bSJed Brown   cid = p4est_quadrant_child_id(&ancestor);
830a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&ancestor, &ancestorcorner, P4EST_CHILDREN - 1 - cid, quadrant->level);
840a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant, &ancestorcorner)) return 1;
850a96aa3bSJed Brown   return 0;
860a96aa3bSJed Brown }
870a96aa3bSJed Brown 
88d71ae5a4SJacob Faibussowitsch static int DMRefinePattern_Fractal(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
89d71ae5a4SJacob Faibussowitsch {
900a96aa3bSJed Brown   int                 cid;
910a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
920a96aa3bSJed Brown 
930a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
940a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
950a96aa3bSJed Brown   if (!quadrant->level) return 1;
960a96aa3bSJed Brown   cid = p4est_quadrant_child_id(quadrant);
970a96aa3bSJed Brown   if (ctx->fractal[cid ^ ((int)(quadrant->level % P4EST_CHILDREN))]) return 1;
980a96aa3bSJed Brown   return 0;
990a96aa3bSJed Brown }
1000a96aa3bSJed Brown 
1010a96aa3bSJed Brown   /* simplified from MurmurHash3 by Austin Appleby */
1020a96aa3bSJed Brown   #define DMPROT32(x, y) ((x << y) | (x >> (32 - y)))
103d71ae5a4SJacob Faibussowitsch static uint32_t DMPforestHash(const uint32_t *blocks, uint32_t nblocks)
104d71ae5a4SJacob Faibussowitsch {
1050a96aa3bSJed Brown   uint32_t c1   = 0xcc9e2d51;
1060a96aa3bSJed Brown   uint32_t c2   = 0x1b873593;
1070a96aa3bSJed Brown   uint32_t r1   = 15;
1080a96aa3bSJed Brown   uint32_t r2   = 13;
1090a96aa3bSJed Brown   uint32_t m    = 5;
1100a96aa3bSJed Brown   uint32_t n    = 0xe6546b64;
1110a96aa3bSJed Brown   uint32_t hash = 0;
1120a96aa3bSJed Brown   int      len  = nblocks * 4;
1130a96aa3bSJed Brown   uint32_t i;
1140a96aa3bSJed Brown 
1150a96aa3bSJed Brown   for (i = 0; i < nblocks; i++) {
1160a96aa3bSJed Brown     uint32_t k;
1170a96aa3bSJed Brown 
1180a96aa3bSJed Brown     k = blocks[i];
1190a96aa3bSJed Brown     k *= c1;
1200a96aa3bSJed Brown     k = DMPROT32(k, r1);
1210a96aa3bSJed Brown     k *= c2;
1220a96aa3bSJed Brown 
1230a96aa3bSJed Brown     hash ^= k;
1240a96aa3bSJed Brown     hash = DMPROT32(hash, r2) * m + n;
1250a96aa3bSJed Brown   }
1260a96aa3bSJed Brown 
1270a96aa3bSJed Brown   hash ^= len;
1280a96aa3bSJed Brown   hash ^= (hash >> 16);
1290a96aa3bSJed Brown   hash *= 0x85ebca6b;
1300a96aa3bSJed Brown   hash ^= (hash >> 13);
1310a96aa3bSJed Brown   hash *= 0xc2b2ae35;
1320a96aa3bSJed Brown   hash ^= (hash >> 16);
1330a96aa3bSJed Brown 
1340a96aa3bSJed Brown   return hash;
1350a96aa3bSJed Brown }
1360a96aa3bSJed Brown 
1370a96aa3bSJed Brown   #if defined(UINT32_MAX)
1380a96aa3bSJed Brown     #define DMP4EST_HASH_MAX UINT32_MAX
1390a96aa3bSJed Brown   #else
1400a96aa3bSJed Brown     #define DMP4EST_HASH_MAX ((uint32_t)0xffffffff)
1410a96aa3bSJed Brown   #endif
1420a96aa3bSJed Brown 
143d71ae5a4SJacob Faibussowitsch static int DMRefinePattern_Hash(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
144d71ae5a4SJacob Faibussowitsch {
1450a96aa3bSJed Brown   uint32_t            data[5];
1460a96aa3bSJed Brown   uint32_t            result;
1470a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
1480a96aa3bSJed Brown 
1490a96aa3bSJed Brown   ctx = (DMRefinePatternCtx *)p4est->user_pointer;
1500a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
1510a96aa3bSJed Brown   data[0] = ((uint32_t)quadrant->level) << 24;
1520a96aa3bSJed Brown   data[1] = (uint32_t)which_tree;
1530a96aa3bSJed Brown   data[2] = (uint32_t)quadrant->x;
1540a96aa3bSJed Brown   data[3] = (uint32_t)quadrant->y;
1550a96aa3bSJed Brown   #if defined(P4_TO_P8)
1560a96aa3bSJed Brown   data[4] = (uint32_t)quadrant->z;
1570a96aa3bSJed Brown   #endif
1580a96aa3bSJed Brown 
1590a96aa3bSJed Brown   result = DMPforestHash(data, 2 + P4EST_DIM);
1600a96aa3bSJed Brown   if (((double)result / (double)DMP4EST_HASH_MAX) < ctx->hashLikelihood) return 1;
1610a96aa3bSJed Brown   return 0;
1620a96aa3bSJed Brown }
1630a96aa3bSJed Brown 
1640a96aa3bSJed Brown   #define DMConvert_pforest_plex _infix_pforest(DMConvert, _plex)
1650a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM, DMType, DM *);
1660a96aa3bSJed Brown 
1670a96aa3bSJed Brown   #define DMFTopology_pforest _append_pforest(DMFTopology)
1680a96aa3bSJed Brown typedef struct {
1690a96aa3bSJed Brown   PetscInt              refct;
1700a96aa3bSJed Brown   p4est_connectivity_t *conn;
1710a96aa3bSJed Brown   p4est_geometry_t     *geom;
1720a96aa3bSJed Brown   PetscInt             *tree_face_to_uniq; /* p4est does not explicitly enumerate facets, but we must to keep track of labels */
1730a96aa3bSJed Brown } DMFTopology_pforest;
1740a96aa3bSJed Brown 
1750a96aa3bSJed Brown   #define DM_Forest_pforest _append_pforest(DM_Forest)
1760a96aa3bSJed Brown typedef struct {
1770a96aa3bSJed Brown   DMFTopology_pforest *topo;
1780a96aa3bSJed Brown   p4est_t             *forest;
1790a96aa3bSJed Brown   p4est_ghost_t       *ghost;
1800a96aa3bSJed Brown   p4est_lnodes_t      *lnodes;
1810a96aa3bSJed Brown   PetscBool            partition_for_coarsening;
1820a96aa3bSJed Brown   PetscBool            coarsen_hierarchy;
1830a96aa3bSJed Brown   PetscBool            labelsFinalized;
1840a96aa3bSJed Brown   PetscBool            adaptivitySuccess;
1850a96aa3bSJed Brown   PetscInt             cLocalStart;
1860a96aa3bSJed Brown   PetscInt             cLocalEnd;
1870a96aa3bSJed Brown   DM                   plex;
1880a96aa3bSJed Brown   char                *ghostName;
1890a96aa3bSJed Brown   PetscSF              pointAdaptToSelfSF;
1900a96aa3bSJed Brown   PetscSF              pointSelfToAdaptSF;
1910a96aa3bSJed Brown   PetscInt            *pointAdaptToSelfCids;
1920a96aa3bSJed Brown   PetscInt            *pointSelfToAdaptCids;
1930a96aa3bSJed Brown } DM_Forest_pforest;
1940a96aa3bSJed Brown 
1950a96aa3bSJed Brown   #define DM_Forest_geometry_pforest _append_pforest(DM_Forest_geometry)
1960a96aa3bSJed Brown typedef struct {
1970a96aa3bSJed Brown   DM base;
1980a96aa3bSJed Brown   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
1990a96aa3bSJed Brown   void             *mapCtx;
2000a96aa3bSJed Brown   PetscInt          coordDim;
2010a96aa3bSJed Brown   p4est_geometry_t *inner;
2029371c9d4SSatish Balay } DM_Forest_geometry_pforest;
2030a96aa3bSJed Brown 
2040a96aa3bSJed Brown   #define GeometryMapping_pforest _append_pforest(GeometryMapping)
205d71ae5a4SJacob Faibussowitsch static void GeometryMapping_pforest(p4est_geometry_t *geom, p4est_topidx_t which_tree, const double abc[3], double xyz[3])
206d71ae5a4SJacob Faibussowitsch {
2070a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest *)geom->user;
2080a96aa3bSJed Brown   PetscReal                   PetscABC[3]  = {0.};
2090a96aa3bSJed Brown   PetscReal                   PetscXYZ[3]  = {0.};
2100a96aa3bSJed Brown   PetscInt                    i, d = PetscMin(3, geom_pforest->coordDim);
2110a96aa3bSJed Brown   double                      ABC[3];
2120a96aa3bSJed Brown   PetscErrorCode              ierr;
2130a96aa3bSJed Brown 
2140a96aa3bSJed Brown   (geom_pforest->inner->X)(geom_pforest->inner, which_tree, abc, ABC);
2150a96aa3bSJed Brown 
2160a96aa3bSJed Brown   for (i = 0; i < d; i++) PetscABC[i] = ABC[i];
2179371c9d4SSatish Balay   ierr = (geom_pforest->map)(geom_pforest->base, (PetscInt)which_tree, geom_pforest->coordDim, PetscABC, PetscXYZ, geom_pforest->mapCtx);
2189371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2190a96aa3bSJed Brown   for (i = 0; i < d; i++) xyz[i] = PetscXYZ[i];
2200a96aa3bSJed Brown }
2210a96aa3bSJed Brown 
2220a96aa3bSJed Brown   #define GeometryDestroy_pforest _append_pforest(GeometryDestroy)
223d71ae5a4SJacob Faibussowitsch static void GeometryDestroy_pforest(p4est_geometry_t *geom)
224d71ae5a4SJacob Faibussowitsch {
2250a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest *)geom->user;
2260a96aa3bSJed Brown   PetscErrorCode              ierr;
2270a96aa3bSJed Brown 
2280a96aa3bSJed Brown   p4est_geometry_destroy(geom_pforest->inner);
2299371c9d4SSatish Balay   ierr = PetscFree(geom->user);
2309371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2319371c9d4SSatish Balay   ierr = PetscFree(geom);
2329371c9d4SSatish Balay   PETSC_P4EST_ASSERT(!ierr);
2330a96aa3bSJed Brown }
2340a96aa3bSJed Brown 
2350a96aa3bSJed Brown   #define DMFTopologyDestroy_pforest _append_pforest(DMFTopologyDestroy)
236d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMFTopologyDestroy_pforest(DMFTopology_pforest **topo)
237d71ae5a4SJacob Faibussowitsch {
2380a96aa3bSJed Brown   PetscFunctionBegin;
2393ba16761SJacob Faibussowitsch   if (!(*topo)) PetscFunctionReturn(PETSC_SUCCESS);
2400a96aa3bSJed Brown   if (--((*topo)->refct) > 0) {
2410a96aa3bSJed Brown     *topo = NULL;
2423ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
2430a96aa3bSJed Brown   }
244792fecdfSBarry Smith   if ((*topo)->geom) PetscCallP4est(p4est_geometry_destroy, ((*topo)->geom));
245792fecdfSBarry Smith   PetscCallP4est(p4est_connectivity_destroy, ((*topo)->conn));
2469566063dSJacob Faibussowitsch   PetscCall(PetscFree((*topo)->tree_face_to_uniq));
2479566063dSJacob Faibussowitsch   PetscCall(PetscFree(*topo));
2480a96aa3bSJed Brown   *topo = NULL;
2493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2500a96aa3bSJed Brown }
2510a96aa3bSJed Brown 
2520a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *, PetscInt **);
2530a96aa3bSJed Brown 
2540a96aa3bSJed Brown   #define DMFTopologyCreateBrick_pforest _append_pforest(DMFTopologyCreateBrick)
255d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMFTopologyCreateBrick_pforest(DM dm, PetscInt N[], PetscInt P[], PetscReal B[], DMFTopology_pforest **topo, PetscBool useMorton)
256d71ae5a4SJacob Faibussowitsch {
2570a96aa3bSJed Brown   double  *vertices;
2580a96aa3bSJed Brown   PetscInt i, numVerts;
2590a96aa3bSJed Brown 
2600a96aa3bSJed Brown   PetscFunctionBegin;
26128b400f6SJacob Faibussowitsch   PetscCheck(useMorton, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Lexicographic ordering not implemented yet");
2624dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(topo));
2630a96aa3bSJed Brown 
2640a96aa3bSJed Brown   (*topo)->refct = 1;
2650a96aa3bSJed Brown   #if !defined(P4_TO_P8)
266792fecdfSBarry 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));
2670a96aa3bSJed Brown   #else
268792fecdfSBarry 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));
2690a96aa3bSJed Brown   #endif
2700a96aa3bSJed Brown   numVerts = (*topo)->conn->num_vertices;
2710a96aa3bSJed Brown   vertices = (*topo)->conn->vertices;
2720a96aa3bSJed Brown   for (i = 0; i < 3 * numVerts; i++) {
2730a96aa3bSJed Brown     PetscInt j = i % 3;
2740a96aa3bSJed Brown 
2750a96aa3bSJed Brown     vertices[i] = B[2 * j] + (vertices[i] / N[j]) * (B[2 * j + 1] - B[2 * j]);
2760a96aa3bSJed Brown   }
2770a96aa3bSJed Brown   (*topo)->geom = NULL;
2789566063dSJacob Faibussowitsch   PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn, &(*topo)->tree_face_to_uniq));
2793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
2800a96aa3bSJed Brown }
2810a96aa3bSJed Brown 
2820a96aa3bSJed Brown   #define DMFTopologyCreate_pforest _append_pforest(DMFTopologyCreate)
283d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMFTopologyCreate_pforest(DM dm, DMForestTopology topologyName, DMFTopology_pforest **topo)
284d71ae5a4SJacob Faibussowitsch {
2850a96aa3bSJed Brown   const char *name = (const char *)topologyName;
2860a96aa3bSJed Brown   const char *prefix;
2870a96aa3bSJed Brown   PetscBool   isBrick, isShell, isSphere, isMoebius;
2880a96aa3bSJed Brown 
2890a96aa3bSJed Brown   PetscFunctionBegin;
2900a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
2914f572ea9SToby Isaac   PetscAssertPointer(name, 2);
2924f572ea9SToby Isaac   PetscAssertPointer(topo, 3);
2939566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "brick", &isBrick));
2949566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "shell", &isShell));
2959566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "sphere", &isSphere));
2969566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name, "moebius", &isMoebius));
2979566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
2980a96aa3bSJed Brown   if (isBrick) {
2990a96aa3bSJed Brown     PetscBool flgN, flgP, flgM, flgB, useMorton = PETSC_TRUE, periodic = PETSC_FALSE;
3000a96aa3bSJed Brown     PetscInt  N[3] = {2, 2, 2}, P[3] = {0, 0, 0}, nretN = P4EST_DIM, nretP = P4EST_DIM, nretB = 2 * P4EST_DIM, i;
3014fb89dddSMatthew 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};
3020a96aa3bSJed Brown 
3030a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
3049566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_size", N, &nretN, &flgN));
3059566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_periodicity", P, &nretP, &flgP));
3069566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_bounds", B, &nretB, &flgB));
3079566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, prefix, "-dm_p4est_brick_use_morton_curve", &useMorton, &flgM));
3081dca8a05SBarry 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);
3091dca8a05SBarry 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);
3101dca8a05SBarry 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);
3110a96aa3bSJed Brown     }
3120a96aa3bSJed Brown     for (i = 0; i < P4EST_DIM; i++) {
3130a96aa3bSJed Brown       P[i]     = (P[i] ? DM_BOUNDARY_PERIODIC : DM_BOUNDARY_NONE);
3140a96aa3bSJed Brown       periodic = (PetscBool)(P[i] || periodic);
3150a96aa3bSJed Brown       if (!flgB) B[2 * i + 1] = N[i];
3166858538eSMatthew G. Knepley       if (P[i]) {
3174fb89dddSMatthew G. Knepley         Lstart[i]  = B[2 * i + 0];
3184fb89dddSMatthew G. Knepley         L[i]       = B[2 * i + 1] - B[2 * i + 0];
3196858538eSMatthew G. Knepley         maxCell[i] = 1.1 * (L[i] / N[i]);
3206858538eSMatthew G. Knepley       }
3210a96aa3bSJed Brown     }
3229566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreateBrick_pforest(dm, N, P, B, topo, useMorton));
3234fb89dddSMatthew G. Knepley     if (periodic) PetscCall(DMSetPeriodicity(dm, maxCell, Lstart, L));
3240a96aa3bSJed Brown   } else {
3254dfa11a4SJacob Faibussowitsch     PetscCall(PetscNew(topo));
3260a96aa3bSJed Brown 
3270a96aa3bSJed Brown     (*topo)->refct = 1;
328792fecdfSBarry Smith     PetscCallP4estReturn((*topo)->conn, p4est_connectivity_new_byname, (name));
3290a96aa3bSJed Brown     (*topo)->geom = NULL;
3301baa6e33SBarry Smith     if (isMoebius) PetscCall(DMSetCoordinateDim(dm, 3));
3310a96aa3bSJed Brown   #if defined(P4_TO_P8)
3320a96aa3bSJed Brown     if (isShell) {
3330a96aa3bSJed Brown       PetscReal R2 = 1., R1 = .55;
3340a96aa3bSJed Brown 
3350a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3369566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_shell_outer_radius", &R2, NULL));
3379566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_shell_inner_radius", &R1, NULL));
3380a96aa3bSJed Brown       }
339792fecdfSBarry Smith       PetscCallP4estReturn((*topo)->geom, p8est_geometry_new_shell, ((*topo)->conn, R2, R1));
3400a96aa3bSJed Brown     } else if (isSphere) {
3410a96aa3bSJed Brown       PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856;
3420a96aa3bSJed Brown 
3430a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3449566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_outer_radius", &R2, NULL));
3459566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_inner_radius", &R1, NULL));
3469566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_sphere_core_radius", &R0, NULL));
3470a96aa3bSJed Brown       }
348792fecdfSBarry Smith       PetscCallP4estReturn((*topo)->geom, p8est_geometry_new_sphere, ((*topo)->conn, R2, R1, R0));
3490a96aa3bSJed Brown     }
3500a96aa3bSJed Brown   #endif
3519566063dSJacob Faibussowitsch     PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn, &(*topo)->tree_face_to_uniq));
3520a96aa3bSJed Brown   }
3533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3540a96aa3bSJed Brown }
3550a96aa3bSJed Brown 
3560a96aa3bSJed Brown   #define DMConvert_plex_pforest _append_pforest(DMConvert_plex)
357d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest)
358d71ae5a4SJacob Faibussowitsch {
3590a96aa3bSJed Brown   MPI_Comm  comm;
3600a96aa3bSJed Brown   PetscBool isPlex;
3610a96aa3bSJed Brown   PetscInt  dim;
3620a96aa3bSJed Brown   void     *ctx;
3630a96aa3bSJed Brown 
3640a96aa3bSJed Brown   PetscFunctionBegin;
3650a96aa3bSJed Brown 
3660a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3670a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
3689566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
36928b400f6SJacob Faibussowitsch   PetscCheck(isPlex, comm, PETSC_ERR_ARG_WRONG, "Expected DM type %s, got %s", DMPLEX, ((PetscObject)dm)->type_name);
3709566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
37163a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Expected DM dimension %d, got %" PetscInt_FMT, P4EST_DIM, dim);
3729566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, pforest));
3739566063dSJacob Faibussowitsch   PetscCall(DMSetType(*pforest, DMPFOREST));
3749566063dSJacob Faibussowitsch   PetscCall(DMForestSetBaseDM(*pforest, dm));
3759566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dm, &ctx));
3769566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(*pforest, ctx));
3779566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *pforest));
3783ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3790a96aa3bSJed Brown }
3800a96aa3bSJed Brown 
3810a96aa3bSJed Brown   #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
382d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestDestroy_pforest(DM dm)
383d71ae5a4SJacob Faibussowitsch {
3840a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
3850a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
3860a96aa3bSJed Brown 
3870a96aa3bSJed Brown   PetscFunctionBegin;
3880a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
389792fecdfSBarry Smith   if (pforest->lnodes) PetscCallP4est(p4est_lnodes_destroy, (pforest->lnodes));
3900a96aa3bSJed Brown   pforest->lnodes = NULL;
391792fecdfSBarry Smith   if (pforest->ghost) PetscCallP4est(p4est_ghost_destroy, (pforest->ghost));
3920a96aa3bSJed Brown   pforest->ghost = NULL;
393792fecdfSBarry Smith   if (pforest->forest) PetscCallP4est(p4est_destroy, (pforest->forest));
3940a96aa3bSJed Brown   pforest->forest = NULL;
3959566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&pforest->topo));
3969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_plex_pforest) "_C", NULL));
3979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_pforest_plex) "_C", NULL));
3982e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMSetUpGLVisViewer_C", NULL));
3999566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", NULL));
4002e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", NULL));
4012e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", NULL));
4029566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->ghostName));
4039566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&pforest->plex));
4049566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
4059566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
4069566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
4079566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
4089566063dSJacob Faibussowitsch   PetscCall(PetscFree(forest->data));
4093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4100a96aa3bSJed Brown }
4110a96aa3bSJed Brown 
4120a96aa3bSJed Brown   #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
413d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm)
414d71ae5a4SJacob Faibussowitsch {
4150a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
4160a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest *)((DM_Forest *)tdm->data)->data;
4170a96aa3bSJed Brown 
4180a96aa3bSJed Brown   PetscFunctionBegin;
4190a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
4209566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&(tpforest->topo)));
4210a96aa3bSJed Brown   tpforest->topo = pforest->topo;
4223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4230a96aa3bSJed Brown }
4240a96aa3bSJed Brown 
4250a96aa3bSJed Brown   #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
4260a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM, p4est_connectivity_t **, PetscInt **);
4270a96aa3bSJed Brown 
4289371c9d4SSatish Balay typedef struct _PforestAdaptCtx {
4290a96aa3bSJed Brown   PetscInt  maxLevel;
4300a96aa3bSJed Brown   PetscInt  minLevel;
4310a96aa3bSJed Brown   PetscInt  currLevel;
4320a96aa3bSJed Brown   PetscBool anyChange;
4339371c9d4SSatish Balay } PforestAdaptCtx;
4340a96aa3bSJed Brown 
435d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_currlevel(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
436d71ae5a4SJacob Faibussowitsch {
4370a96aa3bSJed Brown   PforestAdaptCtx *ctx       = (PforestAdaptCtx *)p4est->user_pointer;
4380a96aa3bSJed Brown   PetscInt         minLevel  = ctx->minLevel;
4390a96aa3bSJed Brown   PetscInt         currLevel = ctx->currLevel;
4400a96aa3bSJed Brown 
4410a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4420a96aa3bSJed Brown   return (int)((PetscInt)quadrants[0]->level == currLevel);
4430a96aa3bSJed Brown }
4440a96aa3bSJed Brown 
445d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_uniform(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
446d71ae5a4SJacob Faibussowitsch {
4470a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4480a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4490a96aa3bSJed Brown 
4500a96aa3bSJed Brown   return (int)((PetscInt)quadrants[0]->level > minLevel);
4510a96aa3bSJed Brown }
4520a96aa3bSJed Brown 
453d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_flag_any(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
454d71ae5a4SJacob Faibussowitsch {
4550a96aa3bSJed Brown   PetscInt         i;
4560a96aa3bSJed Brown   PetscBool        any      = PETSC_FALSE;
4570a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4580a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4590a96aa3bSJed Brown 
4600a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4610a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4620a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
4630a96aa3bSJed Brown       any = PETSC_FALSE;
4640a96aa3bSJed Brown       break;
4650a96aa3bSJed Brown     }
4660a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
4670a96aa3bSJed Brown       any = PETSC_TRUE;
4680a96aa3bSJed Brown       break;
4690a96aa3bSJed Brown     }
4700a96aa3bSJed Brown   }
4710a96aa3bSJed Brown   return any ? 1 : 0;
4720a96aa3bSJed Brown }
4730a96aa3bSJed Brown 
474d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_flag_all(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
475d71ae5a4SJacob Faibussowitsch {
4760a96aa3bSJed Brown   PetscInt         i;
4770a96aa3bSJed Brown   PetscBool        all      = PETSC_TRUE;
4780a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4790a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4800a96aa3bSJed Brown 
4810a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4820a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4830a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
4840a96aa3bSJed Brown       all = PETSC_FALSE;
4850a96aa3bSJed Brown       break;
4860a96aa3bSJed Brown     }
4870a96aa3bSJed Brown   }
4880a96aa3bSJed Brown   return all ? 1 : 0;
4890a96aa3bSJed Brown }
4900a96aa3bSJed Brown 
491d71ae5a4SJacob Faibussowitsch static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
492d71ae5a4SJacob Faibussowitsch {
4930a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
4940a96aa3bSJed Brown }
4950a96aa3bSJed Brown 
496d71ae5a4SJacob Faibussowitsch static int pforest_refine_uniform(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
497d71ae5a4SJacob Faibussowitsch {
4980a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4990a96aa3bSJed Brown   PetscInt         maxLevel = ctx->maxLevel;
5000a96aa3bSJed Brown 
5010a96aa3bSJed Brown   return ((PetscInt)quadrant->level < maxLevel);
5020a96aa3bSJed Brown }
5030a96aa3bSJed Brown 
504d71ae5a4SJacob Faibussowitsch static int pforest_refine_flag(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
505d71ae5a4SJacob Faibussowitsch {
5060a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
5070a96aa3bSJed Brown   PetscInt         maxLevel = ctx->maxLevel;
5080a96aa3bSJed Brown 
5090a96aa3bSJed Brown   if ((PetscInt)quadrant->level >= maxLevel) return 0;
5100a96aa3bSJed Brown 
5110a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
5120a96aa3bSJed Brown }
5130a96aa3bSJed Brown 
514d71ae5a4SJacob 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)
515d71ae5a4SJacob Faibussowitsch {
5160a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
5170a96aa3bSJed Brown   p4est_topidx_t t;
5180a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
5190a96aa3bSJed Brown 
5200a96aa3bSJed Brown   PetscFunctionBegin;
5210a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
5220a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t *)p4estFrom->trees->array)[t]);
5230a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t *)p4estTo->trees->array)[t]);
5240a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
5250a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
5260a96aa3bSJed Brown     PetscInt          numFrom   = (PetscInt)treeFrom->quadrants.elem_count;
5270a96aa3bSJed Brown     PetscInt          numTo     = (PetscInt)treeTo->quadrants.elem_count;
5280a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t *)treeFrom->quadrants.array;
5290a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t *)treeTo->quadrants.array;
5300a96aa3bSJed Brown     PetscInt          currentFrom, currentTo;
5310a96aa3bSJed Brown     PetscInt          treeOffsetFrom = (PetscInt)treeFrom->quadrants_offset;
5320a96aa3bSJed Brown     PetscInt          treeOffsetTo   = (PetscInt)treeTo->quadrants_offset;
5330a96aa3bSJed Brown     int               comp;
5340a96aa3bSJed Brown 
535792fecdfSBarry Smith     PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (firstFrom, firstTo));
53628b400f6SJacob Faibussowitsch     PetscCheck(comp, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "non-matching partitions");
5370a96aa3bSJed Brown 
5380a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
5390a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
5400a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
5410a96aa3bSJed Brown 
5420a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
5430a96aa3bSJed Brown         if (toLeaves) {
5440a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5450a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
5460a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5470a96aa3bSJed Brown         }
5480a96aa3bSJed Brown         toFineLeaves++;
5490a96aa3bSJed Brown         currentFrom++;
5500a96aa3bSJed Brown         currentTo++;
5510a96aa3bSJed Brown       } else {
5520a96aa3bSJed Brown         int fromIsAncestor;
5530a96aa3bSJed Brown 
554792fecdfSBarry Smith         PetscCallP4estReturn(fromIsAncestor, p4est_quadrant_is_ancestor, (quadFrom, quadTo));
5550a96aa3bSJed Brown         if (fromIsAncestor) {
5560a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5570a96aa3bSJed Brown 
5580a96aa3bSJed Brown           if (toLeaves) {
5590a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5600a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
5610a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5620a96aa3bSJed Brown           }
5630a96aa3bSJed Brown           toFineLeaves++;
5640a96aa3bSJed Brown           currentTo++;
565792fecdfSBarry Smith           PetscCallP4est(p4est_quadrant_last_descendant, (quadFrom, &lastDesc, quadTo->level));
566792fecdfSBarry Smith           PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (quadTo, &lastDesc));
5670a96aa3bSJed Brown           if (comp) currentFrom++;
5680a96aa3bSJed Brown         } else {
5690a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5700a96aa3bSJed Brown 
5710a96aa3bSJed Brown           if (fromLeaves) {
5720a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
5730a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
5740a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
5750a96aa3bSJed Brown           }
5760a96aa3bSJed Brown           fromFineLeaves++;
5770a96aa3bSJed Brown           currentFrom++;
578792fecdfSBarry Smith           PetscCallP4est(p4est_quadrant_last_descendant, (quadTo, &lastDesc, quadFrom->level));
579792fecdfSBarry Smith           PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (quadFrom, &lastDesc));
5800a96aa3bSJed Brown           if (comp) currentTo++;
5810a96aa3bSJed Brown         }
5820a96aa3bSJed Brown       }
5830a96aa3bSJed Brown     }
5840a96aa3bSJed Brown   }
5850a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
5860a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
5873ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5880a96aa3bSJed Brown }
5890a96aa3bSJed Brown 
5900a96aa3bSJed Brown /* Compute the maximum level across all the trees */
591d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev)
592d71ae5a4SJacob Faibussowitsch {
5930a96aa3bSJed Brown   p4est_topidx_t     t, flt, llt;
5940a96aa3bSJed Brown   DM_Forest         *forest      = (DM_Forest *)dm->data;
5950a96aa3bSJed Brown   DM_Forest_pforest *pforest     = (DM_Forest_pforest *)forest->data;
5960a96aa3bSJed Brown   PetscInt           maxlevelloc = 0;
5970a96aa3bSJed Brown   p4est_t           *p4est;
5980a96aa3bSJed Brown 
5990a96aa3bSJed Brown   PetscFunctionBegin;
60028b400f6SJacob Faibussowitsch   PetscCheck(pforest, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing DM_Forest_pforest");
60128b400f6SJacob Faibussowitsch   PetscCheck(pforest->forest, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing p4est_t");
6020a96aa3bSJed Brown   p4est = pforest->forest;
6030a96aa3bSJed Brown   flt   = p4est->first_local_tree;
6040a96aa3bSJed Brown   llt   = p4est->last_local_tree;
6050a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
6060a96aa3bSJed Brown     p4est_tree_t *tree = &(((p4est_tree_t *)p4est->trees->array)[t]);
6070a96aa3bSJed Brown     maxlevelloc        = PetscMax((PetscInt)tree->maxlevel, maxlevelloc);
6080a96aa3bSJed Brown   }
6091c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&maxlevelloc, lev, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
6103ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6110a96aa3bSJed Brown }
6120a96aa3bSJed Brown 
6130a96aa3bSJed Brown /* Puts identity in coarseToFine */
6140a96aa3bSJed Brown /* assumes a matching partition */
615d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine)
616d71ae5a4SJacob Faibussowitsch {
6170a96aa3bSJed Brown   p4est_topidx_t flt, llt;
6180a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
6190a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
6200a96aa3bSJed Brown   PetscInt      *fromLeaves = NULL, *toLeaves = NULL;
6210a96aa3bSJed Brown   PetscSFNode   *fromRoots = NULL, *toRoots = NULL;
6220a96aa3bSJed Brown 
6230a96aa3bSJed Brown   PetscFunctionBegin;
6240a96aa3bSJed Brown   flt = p4estFrom->first_local_tree;
6250a96aa3bSJed Brown   llt = p4estFrom->last_local_tree;
6269566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &fromCoarse));
62748a46eb9SPierre Jolivet   if (toCoarseFromFine) PetscCall(PetscSFCreate(comm, &toCoarse));
6280a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
6290a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
6309566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom, FromOffset, p4estTo, ToOffset, flt, llt, &numLeavesTo, NULL, NULL, &numLeavesFrom, NULL, NULL));
6319566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo, &toLeaves));
6329566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo, &fromRoots));
6330a96aa3bSJed Brown   if (toCoarseFromFine) {
6349566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom, &fromLeaves));
6359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom, &fromRoots));
6360a96aa3bSJed Brown   }
6379566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom, FromOffset, p4estTo, ToOffset, flt, llt, &numLeavesTo, toLeaves, fromRoots, &numLeavesFrom, fromLeaves, toRoots));
6380a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
6399566063dSJacob Faibussowitsch     PetscCall(PetscFree(toLeaves));
6409566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(fromCoarse, numRootsFrom, numLeavesTo, NULL, PETSC_OWN_POINTER, fromRoots, PETSC_OWN_POINTER));
6411baa6e33SBarry Smith   } else PetscCall(PetscSFSetGraph(fromCoarse, numRootsFrom, numLeavesTo, toLeaves, PETSC_OWN_POINTER, fromRoots, PETSC_OWN_POINTER));
6420a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
6430a96aa3bSJed Brown   if (toCoarseFromFine) {
6449566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(toCoarse, numRootsTo, numLeavesFrom, fromLeaves, PETSC_OWN_POINTER, toRoots, PETSC_OWN_POINTER));
6450a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
6460a96aa3bSJed Brown   }
6473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6480a96aa3bSJed Brown }
6490a96aa3bSJed Brown 
6500a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
651d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB)
652d71ae5a4SJacob Faibussowitsch {
6530a96aa3bSJed Brown   p4est_quadrant_t *myCoarseStart = &(p4estA->global_first_position[rank]);
6540a96aa3bSJed Brown   p4est_quadrant_t *myCoarseEnd   = &(p4estA->global_first_position[rank + 1]);
6550a96aa3bSJed Brown   p4est_quadrant_t *globalFirstB  = p4estB->global_first_position;
6560a96aa3bSJed Brown 
6570a96aa3bSJed Brown   PetscFunctionBegin;
6580a96aa3bSJed Brown   *startB = -1;
6590a96aa3bSJed Brown   *endB   = -1;
6600a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
6610a96aa3bSJed Brown     PetscInt lo, hi, guess;
6620a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
6630a96aa3bSJed Brown     lo    = 0;
6640a96aa3bSJed Brown     hi    = size;
6650a96aa3bSJed Brown     guess = rank;
6660a96aa3bSJed Brown     while (1) {
6670a96aa3bSJed Brown       int startCompMy, myCompEnd;
6680a96aa3bSJed Brown 
669792fecdfSBarry Smith       PetscCallP4estReturn(startCompMy, p4est_quadrant_compare_piggy, (&globalFirstB[guess], myCoarseStart));
670792fecdfSBarry Smith       PetscCallP4estReturn(myCompEnd, p4est_quadrant_compare_piggy, (myCoarseStart, &globalFirstB[guess + 1]));
6710a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
6720a96aa3bSJed Brown         *startB = guess;
6730a96aa3bSJed Brown         break;
6740a96aa3bSJed Brown       } else if (startCompMy > 0) { /* guess is to high */
6750a96aa3bSJed Brown         hi = guess;
6760a96aa3bSJed Brown       } else { /* guess is to low */
6770a96aa3bSJed Brown         lo = guess + 1;
6780a96aa3bSJed Brown       }
6790a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6800a96aa3bSJed Brown     }
6810a96aa3bSJed Brown     /* reset bounds, but not guess */
6820a96aa3bSJed Brown     lo = 0;
6830a96aa3bSJed Brown     hi = size;
6840a96aa3bSJed Brown     while (1) {
6850a96aa3bSJed Brown       int startCompMy, myCompEnd;
6860a96aa3bSJed Brown 
687792fecdfSBarry Smith       PetscCallP4estReturn(startCompMy, p4est_quadrant_compare_piggy, (&globalFirstB[guess], myCoarseEnd));
688792fecdfSBarry Smith       PetscCallP4estReturn(myCompEnd, p4est_quadrant_compare_piggy, (myCoarseEnd, &globalFirstB[guess + 1]));
6890a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
6900a96aa3bSJed Brown         *endB = guess + 1;
6910a96aa3bSJed Brown         break;
6920a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
6930a96aa3bSJed Brown         hi = guess;
6940a96aa3bSJed Brown       } else { /* guess is to low */
6950a96aa3bSJed Brown         lo = guess + 1;
6960a96aa3bSJed Brown       }
6970a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6980a96aa3bSJed Brown     }
6990a96aa3bSJed Brown   }
7003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
7010a96aa3bSJed Brown }
7020a96aa3bSJed Brown 
7030a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM, DM *);
7040a96aa3bSJed Brown 
7050a96aa3bSJed Brown   #define DMSetUp_pforest _append_pforest(DMSetUp)
706d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSetUp_pforest(DM dm)
707d71ae5a4SJacob Faibussowitsch {
7080a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
7090a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
7100a96aa3bSJed Brown   DM                 base, adaptFrom;
7110a96aa3bSJed Brown   DMForestTopology   topoName;
7120a96aa3bSJed Brown   PetscSF            preCoarseToFine = NULL, coarseToPreFine = NULL;
7130a96aa3bSJed Brown   PforestAdaptCtx    ctx;
7140a96aa3bSJed Brown 
7150a96aa3bSJed Brown   PetscFunctionBegin;
7160a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
7170a96aa3bSJed Brown   ctx.maxLevel  = 0;
7180a96aa3bSJed Brown   ctx.currLevel = 0;
7190a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
7200a96aa3bSJed Brown   /* sanity check */
7219566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm, &adaptFrom));
7229566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
7239566063dSJacob Faibussowitsch   PetscCall(DMForestGetTopology(dm, &topoName));
7241dca8a05SBarry 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");
7250a96aa3bSJed Brown 
7260a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
7270a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
7280a96aa3bSJed Brown     PetscBool          ispforest;
7290a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest *)adaptFrom->data;
7300a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest *)aforest->data;
7310a96aa3bSJed Brown 
7329566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)adaptFrom, DMPFOREST, &ispforest));
73328b400f6SJacob Faibussowitsch     PetscCheck(ispforest, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NOTSAMETYPE, "Trying to adapt from %s, which is not %s", ((PetscObject)adaptFrom)->type_name, DMPFOREST);
73428b400f6SJacob Faibussowitsch     PetscCheck(apforest->topo, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "The pre-adaptation forest must have a topology");
7359566063dSJacob Faibussowitsch     PetscCall(DMSetUp(adaptFrom));
7369566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm, &base));
7379566063dSJacob Faibussowitsch     PetscCall(DMForestGetTopology(dm, &topoName));
7380a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
7390a96aa3bSJed Brown     PetscBool isPlex, isDA;
7400a96aa3bSJed Brown 
7419566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)base, &topoName));
7429566063dSJacob Faibussowitsch     PetscCall(DMForestSetTopology(dm, topoName));
7439566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base, DMPLEX, &isPlex));
7449566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base, DMDA, &isDA));
7450a96aa3bSJed Brown     if (isPlex) {
7460a96aa3bSJed Brown       MPI_Comm              comm = PetscObjectComm((PetscObject)dm);
7470a96aa3bSJed Brown       PetscInt              depth;
7480a96aa3bSJed Brown       PetscMPIInt           size;
7490a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
7500a96aa3bSJed Brown       DMFTopology_pforest  *topo;
7510a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
7520a96aa3bSJed Brown 
7539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepth(base, &depth));
7540a96aa3bSJed Brown       if (depth == 1) {
7550a96aa3bSJed Brown         DM connDM;
7560a96aa3bSJed Brown 
7579566063dSJacob Faibussowitsch         PetscCall(DMPlexInterpolate(base, &connDM));
7580a96aa3bSJed Brown         base = connDM;
7599566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm, base));
7609566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&connDM));
76163a3b9bcSJacob 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);
7629566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(comm, &size));
7630a96aa3bSJed Brown       if (size > 1) {
7640a96aa3bSJed Brown         DM      dmRedundant;
7650a96aa3bSJed Brown         PetscSF sf;
7660a96aa3bSJed Brown 
7679566063dSJacob Faibussowitsch         PetscCall(DMPlexGetRedundantDM(base, &sf, &dmRedundant));
76828b400f6SJacob Faibussowitsch         PetscCheck(dmRedundant, comm, PETSC_ERR_PLIB, "Could not create redundant DM");
7699566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)dmRedundant, "_base_migration_sf", (PetscObject)sf));
7709566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&sf));
7710a96aa3bSJed Brown         base = dmRedundant;
7729566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm, base));
7739566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&dmRedundant));
7740a96aa3bSJed Brown       }
7759566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(base, NULL, "-dm_p4est_base_view"));
7769566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateConnectivity_pforest(base, &conn, &tree_face_to_uniq));
7774dfa11a4SJacob Faibussowitsch       PetscCall(PetscNew(&topo));
7780a96aa3bSJed Brown       topo->refct = 1;
7790a96aa3bSJed Brown       topo->conn  = conn;
7800a96aa3bSJed Brown       topo->geom  = NULL;
7810a96aa3bSJed Brown       {
7820a96aa3bSJed Brown         PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
7830a96aa3bSJed Brown         void *mapCtx;
7840a96aa3bSJed Brown 
7859566063dSJacob Faibussowitsch         PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
7860a96aa3bSJed Brown         if (map) {
7870a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
7880a96aa3bSJed Brown           p4est_geometry_t           *geom;
7890a96aa3bSJed Brown 
7909566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom_pforest));
7919566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinateDim(dm, &geom_pforest->coordDim));
7920a96aa3bSJed Brown           geom_pforest->map    = map;
7930a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
794792fecdfSBarry Smith           PetscCallP4estReturn(geom_pforest->inner, p4est_geometry_new_connectivity, (conn));
7959566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom));
7960a96aa3bSJed Brown           geom->name    = topoName;
7970a96aa3bSJed Brown           geom->user    = geom_pforest;
7980a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
7990a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
8000a96aa3bSJed Brown           topo->geom    = geom;
8010a96aa3bSJed Brown         }
8020a96aa3bSJed Brown       }
8030a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
8040a96aa3bSJed Brown       pforest->topo           = topo;
80528b400f6SJacob Faibussowitsch     } else PetscCheck(!isDA, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Not implemented yet");
8060a96aa3bSJed Brown   #if 0
8070a96aa3bSJed Brown       PetscInt N[3], P[3];
8080a96aa3bSJed Brown 
8090a96aa3bSJed Brown       /* get the sizes, periodicities */
8100a96aa3bSJed Brown       /* ... */
8110a96aa3bSJed Brown                                                                   /* don't use Morton order */
8129566063dSJacob Faibussowitsch       PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE));
8130a96aa3bSJed Brown   #endif
8140a96aa3bSJed Brown     {
8150a96aa3bSJed Brown       PetscInt numLabels, l;
8160a96aa3bSJed Brown 
8179566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(base, &numLabels));
8180a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
8190a96aa3bSJed Brown         PetscBool   isDepth, isGhost, isVTK, isDim, isCellType;
8200a96aa3bSJed Brown         DMLabel     label, labelNew;
8210a96aa3bSJed Brown         PetscInt    defVal;
8220a96aa3bSJed Brown         const char *name;
8230a96aa3bSJed Brown 
8249566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(base, l, &name));
8259566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(base, l, &label));
8269566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "depth", &isDepth));
8270a96aa3bSJed Brown         if (isDepth) continue;
8289566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "dim", &isDim));
8290a96aa3bSJed Brown         if (isDim) continue;
8309566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "celltype", &isCellType));
8310a96aa3bSJed Brown         if (isCellType) continue;
8329566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "ghost", &isGhost));
8330a96aa3bSJed Brown         if (isGhost) continue;
8349566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "vtk", &isVTK));
8350a96aa3bSJed Brown         if (isVTK) continue;
8369566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm, name));
8379566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm, name, &labelNew));
8389566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label, &defVal));
8399566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
8400a96aa3bSJed Brown       }
8410a96aa3bSJed Brown       /* map dm points (internal plex) to base
8420a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
8430a96aa3bSJed Brown          and propagating back to the coarsest
8440a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
8450a96aa3bSJed Brown          during DMForestTransferVecFromBase */
8469566063dSJacob Faibussowitsch       PetscCall(DMForestGetMinimumRefinement(dm, &l));
84748a46eb9SPierre Jolivet       if (!l) PetscCall(DMCreateLabel(dm, "_forest_base_subpoint_map"));
8480a96aa3bSJed Brown     }
8490a96aa3bSJed Brown   } else { /* construct from topology name */
8500a96aa3bSJed Brown     DMFTopology_pforest *topo;
8510a96aa3bSJed Brown 
8529566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreate_pforest(dm, topoName, &topo));
8530a96aa3bSJed Brown     pforest->topo = topo;
8540a96aa3bSJed Brown     /* TODO: construct base? */
8550a96aa3bSJed Brown   }
8560a96aa3bSJed Brown 
8570a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
8580a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
8590a96aa3bSJed Brown     DMLabel            adaptLabel;
8600a96aa3bSJed Brown     PetscInt           defaultValue;
8610a96aa3bSJed Brown     PetscInt           numValues, numValuesGlobal, cLocalStart, count;
8620a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest *)adaptFrom->data;
8630a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest *)aforest->data;
8640a96aa3bSJed Brown     PetscBool          computeAdaptSF;
8650a96aa3bSJed Brown     p4est_topidx_t     flt, llt, t;
8660a96aa3bSJed Brown 
8670a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
8680a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
8690a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
8709566063dSJacob Faibussowitsch     PetscCall(DMForestGetComputeAdaptivitySF(dm, &computeAdaptSF));
871792fecdfSBarry Smith     PetscCallP4estReturn(pforest->forest, p4est_copy, (apforest->forest, 0)); /* 0 indicates no data copying */
8729566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm, &adaptLabel));
8730a96aa3bSJed Brown     if (adaptLabel) {
8740a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
8759566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(adaptLabel, &numValues));
876712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&numValues, &numValuesGlobal, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)adaptFrom)));
8779566063dSJacob Faibussowitsch       PetscCall(DMLabelGetDefaultValue(adaptLabel, &defaultValue));
8780a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
8799566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8809566063dSJacob Faibussowitsch         PetscCall(DMPforestGetRefinementLevel(dm, &ctx.currLevel));
8810a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
882792fecdfSBarry Smith         PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_currlevel, NULL));
8830a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
884792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8850a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
88648a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), pforest->forest, 0, apforest->forest, apforest->cLocalStart, &coarseToPreFine, NULL));
8870a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */
8889566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8890a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
890792fecdfSBarry Smith         PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_uniform, NULL));
8910a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
892792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8930a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
89448a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), pforest->forest, 0, apforest->forest, apforest->cLocalStart, &coarseToPreFine, NULL));
8950a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
8969566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &ctx.maxLevel));
8970a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
898792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 0, pforest_refine_uniform, NULL));
8990a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
900792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
9010a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
90248a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), apforest->forest, apforest->cLocalStart, pforest->forest, 0, &preCoarseToFine, NULL));
9030a96aa3bSJed Brown       } else if (numValuesGlobal) {
9040a96aa3bSJed Brown         p4est_t                   *p4est = pforest->forest;
9050a96aa3bSJed Brown         PetscInt                  *cellFlags;
9060a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
9070a96aa3bSJed Brown         PetscSF                    cellSF;
9080a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
9090a96aa3bSJed Brown         PetscBool                  adaptAny;
9100a96aa3bSJed Brown 
9119566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &ctx.maxLevel));
9129566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
9139566063dSJacob Faibussowitsch         PetscCall(DMForestGetAdaptivityStrategy(dm, &strategy));
9149566063dSJacob Faibussowitsch         PetscCall(PetscStrncmp(strategy, "any", 3, &adaptAny));
9159566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellChart(adaptFrom, &cStart, &cEnd));
9169566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellSF(adaptFrom, &cellSF));
9179566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cEnd - cStart, &cellFlags));
9189566063dSJacob Faibussowitsch         for (c = cStart; c < cEnd; c++) PetscCall(DMLabelGetValue(adaptLabel, c, &cellFlags[c - cStart]));
9190a96aa3bSJed Brown         if (cellSF) {
9200a96aa3bSJed Brown           if (adaptAny) {
9219566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MAX));
9229566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MAX));
9230a96aa3bSJed Brown           } else {
9249566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MIN));
9259566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MIN));
9260a96aa3bSJed Brown           }
9270a96aa3bSJed Brown         }
9280a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
9290a96aa3bSJed Brown           p4est_tree_t     *tree     = &(((p4est_tree_t *)p4est->trees->array)[t]);
9300a96aa3bSJed Brown           PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count, i;
9310a96aa3bSJed Brown           p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
9320a96aa3bSJed Brown 
9330a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9340a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
9350a96aa3bSJed Brown             q->p.user_int       = cellFlags[count++];
9360a96aa3bSJed Brown           }
9370a96aa3bSJed Brown         }
9389566063dSJacob Faibussowitsch         PetscCall(PetscFree(cellFlags));
9390a96aa3bSJed Brown 
9400a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
941792fecdfSBarry Smith         if (adaptAny) PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_flag_any, pforest_init_determine));
942792fecdfSBarry Smith         else PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_flag_all, pforest_init_determine));
943792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 0, pforest_refine_flag, NULL));
9440a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
945792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
94648a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), apforest->forest, apforest->cLocalStart, pforest->forest, 0, &preCoarseToFine, &coarseToPreFine));
9470a96aa3bSJed Brown       }
9480a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
9490a96aa3bSJed Brown         p4est_tree_t     *atree     = &(((p4est_tree_t *)apforest->forest->trees->array)[t]);
9500a96aa3bSJed Brown         p4est_tree_t     *tree      = &(((p4est_tree_t *)pforest->forest->trees->array)[t]);
9510a96aa3bSJed Brown         PetscInt          anumQuads = (PetscInt)atree->quadrants.elem_count, i;
9520a96aa3bSJed Brown         PetscInt          numQuads  = (PetscInt)tree->quadrants.elem_count;
9530a96aa3bSJed Brown         p4est_quadrant_t *aquads    = (p4est_quadrant_t *)atree->quadrants.array;
9540a96aa3bSJed Brown         p4est_quadrant_t *quads     = (p4est_quadrant_t *)tree->quadrants.array;
9550a96aa3bSJed Brown 
9560a96aa3bSJed Brown         if (anumQuads != numQuads) {
9570a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
9580a96aa3bSJed Brown         } else {
9590a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9600a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
9610a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
9620a96aa3bSJed Brown 
9630a96aa3bSJed Brown             if (aq->level != q->level) {
9640a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
9650a96aa3bSJed Brown               break;
9660a96aa3bSJed Brown             }
9670a96aa3bSJed Brown           }
9680a96aa3bSJed Brown         }
969ad540459SPierre Jolivet         if (ctx.anyChange) break;
9700a96aa3bSJed Brown       }
9710a96aa3bSJed Brown     }
9720a96aa3bSJed Brown     {
9730a96aa3bSJed Brown       PetscInt numLabels, l;
9740a96aa3bSJed Brown 
9759566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(adaptFrom, &numLabels));
9760a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
9770a96aa3bSJed Brown         PetscBool   isDepth, isCellType, isGhost, isVTK;
9780a96aa3bSJed Brown         DMLabel     label, labelNew;
9790a96aa3bSJed Brown         PetscInt    defVal;
9800a96aa3bSJed Brown         const char *name;
9810a96aa3bSJed Brown 
9829566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(adaptFrom, l, &name));
9839566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(adaptFrom, l, &label));
9849566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "depth", &isDepth));
9850a96aa3bSJed Brown         if (isDepth) continue;
9869566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "celltype", &isCellType));
9870a96aa3bSJed Brown         if (isCellType) continue;
9889566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "ghost", &isGhost));
9890a96aa3bSJed Brown         if (isGhost) continue;
9909566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "vtk", &isVTK));
9910a96aa3bSJed Brown         if (isVTK) continue;
9929566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm, name));
9939566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm, name, &labelNew));
9949566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label, &defVal));
9959566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
9960a96aa3bSJed Brown       }
9970a96aa3bSJed Brown     }
9980a96aa3bSJed Brown   } else { /* initial */
9990a96aa3bSJed Brown     PetscInt initLevel, minLevel;
100066c0a4b5SToby Isaac   #if defined(PETSC_HAVE_MPIUNI)
100166c0a4b5SToby Isaac     sc_MPI_Comm comm = sc_MPI_COMM_WORLD;
100266c0a4b5SToby Isaac   #else
100366c0a4b5SToby Isaac     MPI_Comm comm = PetscObjectComm((PetscObject)dm);
100466c0a4b5SToby Isaac   #endif
10050a96aa3bSJed Brown 
10069566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm, &initLevel));
10079566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
10089371c9d4SSatish Balay     PetscCallP4estReturn(pforest->forest, p4est_new_ext,
10099371c9d4SSatish Balay                          (comm, pforest->topo->conn, 0, /* minimum number of quadrants per processor */
10100a96aa3bSJed Brown                           initLevel,                    /* level of refinement */
10110a96aa3bSJed Brown                           1,                            /* uniform refinement */
10120a96aa3bSJed Brown                           0,                            /* we don't allocate any per quadrant data */
10130a96aa3bSJed Brown                           NULL,                         /* there is no special quadrant initialization */
10140a96aa3bSJed Brown                           (void *)dm));                 /* this dm is the user context */
10150a96aa3bSJed Brown 
10160a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10170a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
10180a96aa3bSJed Brown       PetscBool   flgPattern, flgFractal;
10190a96aa3bSJed Brown       PetscInt    corner = 0;
10200a96aa3bSJed Brown       PetscInt    corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
10210a96aa3bSJed Brown       PetscReal   likelihood = 1. / P4EST_DIM;
10220a96aa3bSJed Brown       PetscInt    pattern;
10230a96aa3bSJed Brown       const char *prefix;
10240a96aa3bSJed Brown 
10259566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
10269566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEList(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_pattern", DMRefinePatternName, PATTERN_COUNT, &pattern, &flgPattern));
10279566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_corner", &corner, NULL));
10289566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_fractal_corners", corners, &ncorner, &flgFractal));
10299566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_hash_likelihood", &likelihood, NULL));
10300a96aa3bSJed Brown 
10310a96aa3bSJed Brown       if (flgPattern) {
10320a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
10330a96aa3bSJed Brown         PetscInt            maxLevel;
10340a96aa3bSJed Brown 
10359566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &maxLevel));
10364dfa11a4SJacob Faibussowitsch         PetscCall(PetscNew(&ctx));
10370a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel, P4EST_QMAXLEVEL);
10380a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10390a96aa3bSJed Brown         switch (pattern) {
10400a96aa3bSJed Brown         case PATTERN_HASH:
10410a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
10420a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
10430a96aa3bSJed Brown           break;
10440a96aa3bSJed Brown         case PATTERN_CORNER:
10450a96aa3bSJed Brown           ctx->corner    = corner;
10460a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
10470a96aa3bSJed Brown           break;
1048d71ae5a4SJacob Faibussowitsch         case PATTERN_CENTER:
1049d71ae5a4SJacob Faibussowitsch           ctx->refine_fn = DMRefinePattern_Center;
1050d71ae5a4SJacob Faibussowitsch           break;
10510a96aa3bSJed Brown         case PATTERN_FRACTAL:
10520a96aa3bSJed Brown           if (flgFractal) {
10530a96aa3bSJed Brown             PetscInt i;
10540a96aa3bSJed Brown 
10550a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
10560a96aa3bSJed Brown           } else {
10570a96aa3bSJed Brown   #if !defined(P4_TO_P8)
10580a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
10590a96aa3bSJed Brown   #else
10600a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
10610a96aa3bSJed Brown   #endif
10620a96aa3bSJed Brown           }
10630a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
10640a96aa3bSJed Brown           break;
1065d71ae5a4SJacob Faibussowitsch         default:
1066d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Not a valid refinement pattern");
10670a96aa3bSJed Brown         }
10680a96aa3bSJed Brown 
10690a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)ctx;
1070792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 1, ctx->refine_fn, NULL));
1071792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
10729566063dSJacob Faibussowitsch         PetscCall(PetscFree(ctx));
10730a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
10740a96aa3bSJed Brown       }
10750a96aa3bSJed Brown     }
10760a96aa3bSJed Brown   }
10770a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
10780a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
10790a96aa3bSJed Brown 
10809566063dSJacob Faibussowitsch     PetscCall(DMPforestGetRefinementLevel(dm, &currLevel));
10819566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm, &initLevel));
10829566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
10830a96aa3bSJed Brown     if (currLevel > minLevel) {
10840a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
10850a96aa3bSJed Brown       DMLabel            coarsen;
10860a96aa3bSJed Brown       DM                 coarseDM;
10870a96aa3bSJed Brown 
10889566063dSJacob Faibussowitsch       PetscCall(DMForestTemplate(dm, MPI_COMM_NULL, &coarseDM));
10899566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityPurpose(coarseDM, DM_ADAPT_COARSEN));
10909566063dSJacob Faibussowitsch       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
10919566063dSJacob Faibussowitsch       PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
10929566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityLabel(coarseDM, coarsen));
10939566063dSJacob Faibussowitsch       PetscCall(DMLabelDestroy(&coarsen));
10949566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm, coarseDM));
10959566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)coarseDM));
10960a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
10979566063dSJacob Faibussowitsch       PetscCall(DMForestSetInitialRefinement(coarseDM, initLevel));
10989566063dSJacob Faibussowitsch       PetscCall(DMForestSetMinimumRefinement(coarseDM, minLevel));
10990a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest *)((DM_Forest *)coarseDM->data)->data;
11000a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
11010a96aa3bSJed Brown     }
11020a96aa3bSJed Brown   }
11030a96aa3bSJed Brown 
11040a96aa3bSJed Brown   { /* repartitioning and overlap */
11050a96aa3bSJed Brown     PetscMPIInt size, rank;
11060a96aa3bSJed Brown 
11079566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
11089566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
11090a96aa3bSJed Brown     if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
11100a96aa3bSJed Brown       PetscBool      copyForest  = PETSC_FALSE;
11110a96aa3bSJed Brown       p4est_t       *forest_copy = NULL;
11120a96aa3bSJed Brown       p4est_gloidx_t shipped     = 0;
11130a96aa3bSJed Brown 
11140a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
1115792fecdfSBarry Smith       if (copyForest) PetscCallP4estReturn(forest_copy, p4est_copy, (pforest->forest, 0));
11160a96aa3bSJed Brown 
11170a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
1118792fecdfSBarry Smith         PetscCallP4estReturn(shipped, p4est_partition_ext, (pforest->forest, (int)pforest->partition_for_coarsening, NULL));
11190a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Non-uniform partition cases not implemented yet");
11200a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
11210a96aa3bSJed Brown       if (forest_copy) {
11220a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
11230a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
11240a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
11250a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
11260a96aa3bSJed Brown           PetscSFNode   *repartRoots;
11270a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
11280a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank + 1];
11290a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
11300a96aa3bSJed Brown 
11310a96aa3bSJed Brown           numRoots  = (PetscInt)(forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
11320a96aa3bSJed Brown           numLeaves = (PetscInt)(postEnd - postStart);
11339566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeOverlappingRanks(size, rank, pforest->forest, forest_copy, &pStart, &pEnd));
11349566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1((PetscInt)pforest->forest->local_num_quadrants, &repartRoots));
11350a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
11360a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
11370a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p + 1];
11380a96aa3bSJed Brown             PetscInt       q;
11390a96aa3bSJed Brown 
11400a96aa3bSJed Brown             if (preEnd == preStart) continue;
114108401ef6SPierre Jolivet             PetscCheck(preStart <= postStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad partition overlap computation");
11420a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
11430a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
11440a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
11450a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
11460a96aa3bSJed Brown             }
11470a96aa3bSJed Brown             partOffset = preEnd;
11480a96aa3bSJed Brown           }
11499566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &repartSF));
11509566063dSJacob Faibussowitsch           PetscCall(PetscSFSetGraph(repartSF, numRoots, numLeaves, NULL, PETSC_OWN_POINTER, repartRoots, PETSC_OWN_POINTER));
11519566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(repartSF));
11520a96aa3bSJed Brown           if (preCoarseToFine) {
11530a96aa3bSJed Brown             PetscSF         repartSFembed, preCoarseToFineNew;
11540a96aa3bSJed Brown             PetscInt        nleaves;
11550a96aa3bSJed Brown             const PetscInt *leaves;
11560a96aa3bSJed Brown 
11579566063dSJacob Faibussowitsch             PetscCall(PetscSFSetUp(preCoarseToFine));
11589566063dSJacob Faibussowitsch             PetscCall(PetscSFGetGraph(preCoarseToFine, NULL, &nleaves, &leaves, NULL));
11590a96aa3bSJed Brown             if (leaves) {
11609566063dSJacob Faibussowitsch               PetscCall(PetscSFCreateEmbeddedRootSF(repartSF, nleaves, leaves, &repartSFembed));
11610a96aa3bSJed Brown             } else {
11620a96aa3bSJed Brown               repartSFembed = repartSF;
11639566063dSJacob Faibussowitsch               PetscCall(PetscObjectReference((PetscObject)repartSFembed));
11640a96aa3bSJed Brown             }
11659566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(preCoarseToFine, repartSFembed, &preCoarseToFineNew));
11669566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&preCoarseToFine));
11679566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFembed));
11680a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
11690a96aa3bSJed Brown           }
11700a96aa3bSJed Brown           if (coarseToPreFine) {
11710a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
11720a96aa3bSJed Brown 
11739566063dSJacob Faibussowitsch             PetscCall(PetscSFCreateInverseSF(repartSF, &repartSFinv));
11749566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(repartSFinv, coarseToPreFine, &coarseToPreFineNew));
11759566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&coarseToPreFine));
11769566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFinv));
11770a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
11780a96aa3bSJed Brown           }
11799566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&repartSF));
11800a96aa3bSJed Brown         }
1181792fecdfSBarry Smith         PetscCallP4est(p4est_destroy, (forest_copy));
11820a96aa3bSJed Brown       }
11830a96aa3bSJed Brown     }
11840a96aa3bSJed Brown     if (size > 1) {
11850a96aa3bSJed Brown       PetscInt overlap;
11860a96aa3bSJed Brown 
11879566063dSJacob Faibussowitsch       PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
11880a96aa3bSJed Brown 
11890a96aa3bSJed Brown       if (adaptFrom) {
11900a96aa3bSJed Brown         PetscInt aoverlap;
11910a96aa3bSJed Brown 
11929566063dSJacob Faibussowitsch         PetscCall(DMForestGetPartitionOverlap(adaptFrom, &aoverlap));
1193ad540459SPierre Jolivet         if (aoverlap != overlap) ctx.anyChange = PETSC_TRUE;
11940a96aa3bSJed Brown       }
11950a96aa3bSJed Brown 
11960a96aa3bSJed Brown       if (overlap > 0) {
11970a96aa3bSJed Brown         PetscInt i, cLocalStart;
11980a96aa3bSJed Brown         PetscInt cEnd;
11990a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
12000a96aa3bSJed Brown 
1201792fecdfSBarry Smith         PetscCallP4estReturn(pforest->ghost, p4est_ghost_new, (pforest->forest, P4EST_CONNECT_FULL));
1202792fecdfSBarry Smith         PetscCallP4estReturn(pforest->lnodes, p4est_lnodes_new, (pforest->forest, pforest->ghost, -P4EST_DIM));
1203792fecdfSBarry Smith         PetscCallP4est(p4est_ghost_support_lnodes, (pforest->forest, pforest->lnodes, pforest->ghost));
1204792fecdfSBarry Smith         for (i = 1; i < overlap; i++) PetscCallP4est(p4est_ghost_expand_by_lnodes, (pforest->forest, pforest->lnodes, pforest->ghost));
12050a96aa3bSJed Brown 
12060a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
12070a96aa3bSJed Brown         cEnd                               = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
12080a96aa3bSJed Brown 
12090a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
12100a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
12119566063dSJacob Faibussowitsch           if (adaptFrom) PetscCall(DMForestGetCellSF(adaptFrom, &preCellSF));
12120a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
12139566063dSJacob Faibussowitsch           PetscCall(DMForestGetCellSF(dm, &cellSF));
12140a96aa3bSJed Brown         }
12150a96aa3bSJed Brown         if (preCoarseToFine) {
12160a96aa3bSJed Brown           PetscSF            preCoarseToFineNew;
12170a96aa3bSJed Brown           PetscInt           nleaves, nroots, *leavesNew, i, nleavesNew;
12180a96aa3bSJed Brown           const PetscInt    *leaves;
12190a96aa3bSJed Brown           const PetscSFNode *remotes;
12200a96aa3bSJed Brown           PetscSFNode       *remotesAll;
12210a96aa3bSJed Brown 
12229566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(preCoarseToFine));
12239566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCoarseToFine, &nroots, &nleaves, &leaves, &remotes));
12249566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(cEnd, &remotesAll));
12250a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
12260a96aa3bSJed Brown             remotesAll[i].rank  = -1;
12270a96aa3bSJed Brown             remotesAll[i].index = -1;
12280a96aa3bSJed Brown           }
12290a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
12309566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(cellSF));
12319566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(cellSF, MPIU_2INT, remotesAll, remotesAll, MPI_REPLACE));
12329566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(cellSF, MPIU_2INT, remotesAll, remotesAll, MPI_REPLACE));
12330a96aa3bSJed Brown           nleavesNew = 0;
12340a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12350a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
12360a96aa3bSJed Brown           }
12379566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesNew, &leavesNew));
12380a96aa3bSJed Brown           nleavesNew = 0;
12390a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12400a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
12410a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
12420a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
12430a96aa3bSJed Brown               nleavesNew++;
12440a96aa3bSJed Brown             }
12450a96aa3bSJed Brown           }
12469566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &preCoarseToFineNew));
12470a96aa3bSJed Brown           if (nleavesNew < cEnd) {
12489566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew, nroots, nleavesNew, leavesNew, PETSC_OWN_POINTER, remotesAll, PETSC_COPY_VALUES));
12490a96aa3bSJed Brown           } else { /* all cells are leaves */
12509566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
12519566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew, nroots, nleavesNew, NULL, PETSC_OWN_POINTER, remotesAll, PETSC_COPY_VALUES));
12520a96aa3bSJed Brown           }
12539566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesAll));
12549566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&preCoarseToFine));
12550a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12560a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12570a96aa3bSJed Brown         }
12580a96aa3bSJed Brown         if (coarseToPreFine) {
12590a96aa3bSJed Brown           PetscSF            coarseToPreFineNew;
12600a96aa3bSJed Brown           PetscInt           nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
12610a96aa3bSJed Brown           const PetscInt    *leaves;
12620a96aa3bSJed Brown           const PetscSFNode *remotes;
12630a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
12640a96aa3bSJed Brown 
12659566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(coarseToPreFine));
12669566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseToPreFine, &nroots, &nleaves, &leaves, &remotes));
12679566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCellSF, NULL, &nleavesCellSF, NULL, NULL));
12689566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nroots, &remotesNewRoot));
12699566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleaves, &remotesNew));
12700a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
12710a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
12720a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
12730a96aa3bSJed Brown           }
12749566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(coarseToPreFine, MPIU_2INT, remotesNewRoot, remotesNew, MPI_REPLACE));
12759566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(coarseToPreFine, MPIU_2INT, remotesNewRoot, remotesNew, MPI_REPLACE));
12769566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNewRoot));
12779566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesCellSF, &remotesExpanded));
12780a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12790a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
12800a96aa3bSJed Brown             remotesExpanded[i].index = -1;
12810a96aa3bSJed Brown           }
12820a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
12839566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNew));
12849566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(preCellSF, MPIU_2INT, remotesExpanded, remotesExpanded, MPI_REPLACE));
12859566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(preCellSF, MPIU_2INT, remotesExpanded, remotesExpanded, MPI_REPLACE));
12860a96aa3bSJed Brown 
12870a96aa3bSJed Brown           nleavesExpanded = 0;
12880a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12890a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
12900a96aa3bSJed Brown           }
12919566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesExpanded, &leavesNew));
12920a96aa3bSJed Brown           nleavesExpanded = 0;
12930a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12940a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
12950a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
12960a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
12970a96aa3bSJed Brown               nleavesExpanded++;
12980a96aa3bSJed Brown             }
12990a96aa3bSJed Brown           }
13009566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &coarseToPreFineNew));
13010a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
13029566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew, cEnd, nleavesExpanded, leavesNew, PETSC_OWN_POINTER, remotesExpanded, PETSC_COPY_VALUES));
13030a96aa3bSJed Brown           } else {
13049566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
13059566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew, cEnd, nleavesExpanded, NULL, PETSC_OWN_POINTER, remotesExpanded, PETSC_COPY_VALUES));
13060a96aa3bSJed Brown           }
13079566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesExpanded));
13089566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseToPreFine));
13090a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
13100a96aa3bSJed Brown         }
13110a96aa3bSJed Brown       }
13120a96aa3bSJed Brown     }
13130a96aa3bSJed Brown   }
13140a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
13150a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
13160a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
1317712fec58SPierre Jolivet   PetscCall(MPIU_Allreduce(&ctx.anyChange, &(pforest->adaptivitySuccess), 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
13189566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, NULL));
13193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13200a96aa3bSJed Brown }
13210a96aa3bSJed Brown 
13220a96aa3bSJed Brown   #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
1323d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success)
1324d71ae5a4SJacob Faibussowitsch {
13250a96aa3bSJed Brown   DM_Forest         *forest;
13260a96aa3bSJed Brown   DM_Forest_pforest *pforest;
13270a96aa3bSJed Brown 
13280a96aa3bSJed Brown   PetscFunctionBegin;
13290a96aa3bSJed Brown   forest   = (DM_Forest *)dm->data;
13300a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *)forest->data;
13310a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
13323ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13330a96aa3bSJed Brown }
13340a96aa3bSJed Brown 
13350a96aa3bSJed Brown   #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
1336d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer)
1337d71ae5a4SJacob Faibussowitsch {
13380a96aa3bSJed Brown   DM dm = (DM)odm;
13390a96aa3bSJed Brown 
13400a96aa3bSJed Brown   PetscFunctionBegin;
13410a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13420a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13439566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13440a96aa3bSJed Brown   switch (viewer->format) {
13450a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
13469371c9d4SSatish Balay   case PETSC_VIEWER_ASCII_INFO: {
13470a96aa3bSJed Brown     PetscInt    dim;
13480a96aa3bSJed Brown     const char *name;
13490a96aa3bSJed Brown 
13509566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
13519566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
135263a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "Forest %s in %" PetscInt_FMT " dimensions:\n", name, dim));
135363a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Forest in %" PetscInt_FMT " dimensions:\n", dim));
1354f4d061e9SPierre Jolivet   } /* fall through */
13550a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
13569371c9d4SSatish Balay   case PETSC_VIEWER_LOAD_BALANCE: {
13570a96aa3bSJed Brown     DM plex;
13580a96aa3bSJed Brown 
13599566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dm, &plex));
13609566063dSJacob Faibussowitsch     PetscCall(DMView(plex, viewer));
13619371c9d4SSatish Balay   } break;
1362d71ae5a4SJacob Faibussowitsch   default:
1363d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13640a96aa3bSJed Brown   }
13653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13660a96aa3bSJed Brown }
13670a96aa3bSJed Brown 
13680a96aa3bSJed Brown   #define DMView_VTK_pforest _append_pforest(DMView_VTK)
1369d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer)
1370d71ae5a4SJacob Faibussowitsch {
13710a96aa3bSJed Brown   DM                 dm      = (DM)odm;
13720a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
13730a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
13740a96aa3bSJed Brown   PetscBool          isvtk;
13750a96aa3bSJed Brown   PetscReal          vtkScale = 1. - PETSC_MACHINE_EPSILON;
13760a96aa3bSJed Brown   PetscViewer_VTK   *vtk      = (PetscViewer_VTK *)viewer->data;
13770a96aa3bSJed Brown   const char        *name;
13780a96aa3bSJed Brown   char              *filenameStrip = NULL;
13790a96aa3bSJed Brown   PetscBool          hasExt;
13800a96aa3bSJed Brown   size_t             len;
13810a96aa3bSJed Brown   p4est_geometry_t  *geom;
13820a96aa3bSJed Brown 
13830a96aa3bSJed Brown   PetscFunctionBegin;
13840a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13850a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13869566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13870a96aa3bSJed Brown   geom = pforest->topo->geom;
13889566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
138928b400f6SJacob Faibussowitsch   PetscCheck(isvtk, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
13900a96aa3bSJed Brown   switch (viewer->format) {
13910a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
139228b400f6SJacob Faibussowitsch     PetscCheck(pforest->forest, PetscObjectComm(odm), PETSC_ERR_ARG_WRONG, "DM has not been setup with a valid forest");
13930a96aa3bSJed Brown     name = vtk->filename;
13949566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(name, &len));
13959566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(name + len - 4, ".vtu", &hasExt));
13960a96aa3bSJed Brown     if (hasExt) {
13979566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(name, &filenameStrip));
13980a96aa3bSJed Brown       filenameStrip[len - 4] = '\0';
13990a96aa3bSJed Brown       name                   = filenameStrip;
14000a96aa3bSJed Brown     }
1401792fecdfSBarry Smith     if (!pforest->topo->geom) PetscCallP4estReturn(geom, p4est_geometry_new_connectivity, (pforest->topo->conn));
14020a96aa3bSJed Brown     {
14030a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
14040a96aa3bSJed Brown       int                  footerr;
14050a96aa3bSJed Brown 
1406792fecdfSBarry Smith       PetscCallP4estReturn(pvtk, p4est_vtk_context_new, (pforest->forest, name));
1407792fecdfSBarry Smith       PetscCallP4est(p4est_vtk_context_set_geom, (pvtk, geom));
1408792fecdfSBarry Smith       PetscCallP4est(p4est_vtk_context_set_scale, (pvtk, (double)vtkScale));
1409792fecdfSBarry Smith       PetscCallP4estReturn(pvtk, p4est_vtk_write_header, (pvtk));
141028b400f6SJacob Faibussowitsch       PetscCheck(pvtk, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_header() failed");
14119371c9d4SSatish Balay       PetscCallP4estReturn(pvtk, p4est_vtk_write_cell_dataf,
14129371c9d4SSatish Balay                            (pvtk, 1, /* write tree */
14130a96aa3bSJed Brown                             1,       /* write level */
14140a96aa3bSJed Brown                             1,       /* write rank */
14150a96aa3bSJed Brown                             0,       /* do not wrap rank */
14160a96aa3bSJed Brown                             0,       /* no scalar fields */
14170a96aa3bSJed Brown                             0,       /* no vector fields */
14180a96aa3bSJed Brown                             pvtk));
141928b400f6SJacob Faibussowitsch       PetscCheck(pvtk, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_cell_dataf() failed");
1420792fecdfSBarry Smith       PetscCallP4estReturn(footerr, p4est_vtk_write_footer, (pvtk));
142128b400f6SJacob Faibussowitsch       PetscCheck(!footerr, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_footer() failed");
14220a96aa3bSJed Brown     }
1423792fecdfSBarry Smith     if (!pforest->topo->geom) PetscCallP4est(p4est_geometry_destroy, (geom));
14249566063dSJacob Faibussowitsch     PetscCall(PetscFree(filenameStrip));
14250a96aa3bSJed Brown     break;
1426d71ae5a4SJacob Faibussowitsch   default:
1427d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
14280a96aa3bSJed Brown   }
14293ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14300a96aa3bSJed Brown }
14310a96aa3bSJed Brown 
14320a96aa3bSJed Brown   #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
1433d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer)
1434d71ae5a4SJacob Faibussowitsch {
14350a96aa3bSJed Brown   DM plex;
14360a96aa3bSJed Brown 
14370a96aa3bSJed Brown   PetscFunctionBegin;
14389566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14399566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14409566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14420a96aa3bSJed Brown }
14430a96aa3bSJed Brown 
14440a96aa3bSJed Brown   #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
1445d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer)
1446d71ae5a4SJacob Faibussowitsch {
14470a96aa3bSJed Brown   DM plex;
14480a96aa3bSJed Brown 
14490a96aa3bSJed Brown   PetscFunctionBegin;
14509566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14519566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14529566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14540a96aa3bSJed Brown }
14550a96aa3bSJed Brown 
14560a96aa3bSJed Brown   #define DMView_pforest _append_pforest(DMView)
1457d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer)
1458d71ae5a4SJacob Faibussowitsch {
14590a96aa3bSJed Brown   PetscBool isascii, isvtk, ishdf5, isglvis;
14600a96aa3bSJed Brown 
14610a96aa3bSJed Brown   PetscFunctionBegin;
14620a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14630a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
14649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
14659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
14669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
14679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
14680a96aa3bSJed Brown   if (isascii) {
14699566063dSJacob Faibussowitsch     PetscCall(DMView_ASCII_pforest((PetscObject)dm, viewer));
14700a96aa3bSJed Brown   } else if (isvtk) {
14719566063dSJacob Faibussowitsch     PetscCall(DMView_VTK_pforest((PetscObject)dm, viewer));
14720a96aa3bSJed Brown   } else if (ishdf5) {
14739566063dSJacob Faibussowitsch     PetscCall(DMView_HDF5_pforest(dm, viewer));
14740a96aa3bSJed Brown   } else if (isglvis) {
14759566063dSJacob Faibussowitsch     PetscCall(DMView_GLVis_pforest(dm, viewer));
14760a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer not supported (not VTK, HDF5, or GLVis)");
14773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14780a96aa3bSJed Brown }
14790a96aa3bSJed Brown 
1480d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq)
1481d71ae5a4SJacob Faibussowitsch {
14820a96aa3bSJed Brown   PetscInt *ttf, f, t, g, count;
14830a96aa3bSJed Brown   PetscInt  numFacets;
14840a96aa3bSJed Brown 
14850a96aa3bSJed Brown   PetscFunctionBegin;
14860a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
14879566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFacets, &ttf));
14880a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
14890a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
14900a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
14910a96aa3bSJed Brown       if (ttf[g] == -1) {
14920a96aa3bSJed Brown         PetscInt ng;
14930a96aa3bSJed Brown 
14940a96aa3bSJed Brown         ttf[g]  = count++;
14950a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
14960a96aa3bSJed Brown         ttf[ng] = ttf[g];
14970a96aa3bSJed Brown       }
14980a96aa3bSJed Brown     }
14990a96aa3bSJed Brown   }
15000a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
15013ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15020a96aa3bSJed Brown }
15030a96aa3bSJed Brown 
1504d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq)
1505d71ae5a4SJacob Faibussowitsch {
15060a96aa3bSJed Brown   p4est_topidx_t numTrees, numVerts, numCorns, numCtt;
15070a96aa3bSJed Brown   PetscSection   ctt;
15080a96aa3bSJed Brown   #if defined(P4_TO_P8)
15090a96aa3bSJed Brown   p4est_topidx_t numEdges, numEtt;
15100a96aa3bSJed Brown   PetscSection   ett;
15110a96aa3bSJed Brown   PetscInt       eStart, eEnd, e, ettSize;
15120a96aa3bSJed Brown   PetscInt       vertOff = 1 + P4EST_FACES + P8EST_EDGES;
15130a96aa3bSJed Brown   PetscInt       edgeOff = 1 + P4EST_FACES;
15140a96aa3bSJed Brown   #else
15150a96aa3bSJed Brown   PetscInt vertOff = 1 + P4EST_FACES;
15160a96aa3bSJed Brown   #endif
15170a96aa3bSJed Brown   p4est_connectivity_t *conn;
15180a96aa3bSJed Brown   PetscInt              cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
15190a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
15200a96aa3bSJed Brown   PetscInt             *ttf;
15210a96aa3bSJed Brown 
15220a96aa3bSJed Brown   PetscFunctionBegin;
15230a96aa3bSJed Brown   /* 1: count objects, allocate */
15249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
15259566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cEnd - cStart, &numTrees));
15260a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
15279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
15289566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(vEnd - vStart, &numCorns));
15299566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &ctt));
15309566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ctt, vStart, vEnd));
15310a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
15320a96aa3bSJed Brown     PetscInt s;
15330a96aa3bSJed Brown 
15349566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
15350a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15360a96aa3bSJed Brown       PetscInt p = star[2 * s];
15370a96aa3bSJed Brown 
15380a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15390a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
15400a96aa3bSJed Brown          * only protects against periodicity problems */
15419566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
154263a3b9bcSJacob 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);
15430a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
15440a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
15450a96aa3bSJed Brown 
15461dca8a05SBarry Smith           PetscCheck(cellVert >= vStart && cellVert < vEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure: vertices");
154748a46eb9SPierre Jolivet           if (cellVert == v) PetscCall(PetscSectionAddDof(ctt, v, 1));
15480a96aa3bSJed Brown         }
15499566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
15500a96aa3bSJed Brown       }
15510a96aa3bSJed Brown     }
15529566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
15530a96aa3bSJed Brown   }
15549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ctt));
15559566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ctt, &cttSize));
15569566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cttSize, &numCtt));
15570a96aa3bSJed Brown   #if defined(P4_TO_P8)
15589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, P4EST_DIM - 1, &eStart, &eEnd));
15599566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(eEnd - eStart, &numEdges));
15609566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &ett));
15619566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ett, eStart, eEnd));
15620a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
15630a96aa3bSJed Brown     PetscInt s;
15640a96aa3bSJed Brown 
15659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
15660a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15670a96aa3bSJed Brown       PetscInt p = star[2 * s];
15680a96aa3bSJed Brown 
15690a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15700a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
15710a96aa3bSJed Brown          * only protects against periodicity problems */
15729566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
157308401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cell with wrong closure size");
15740a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
15750a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
15760a96aa3bSJed Brown 
15771dca8a05SBarry Smith           PetscCheck(cellEdge >= eStart && cellEdge < eEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure: edges");
157848a46eb9SPierre Jolivet           if (cellEdge == e) PetscCall(PetscSectionAddDof(ett, e, 1));
15790a96aa3bSJed Brown         }
15809566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
15810a96aa3bSJed Brown       }
15820a96aa3bSJed Brown     }
15839566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
15840a96aa3bSJed Brown   }
15859566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ett));
15869566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ett, &ettSize));
15879566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(ettSize, &numEtt));
15880a96aa3bSJed Brown 
15890a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
1590792fecdfSBarry Smith   PetscCallP4estReturn(conn, p8est_connectivity_new, (numVerts, numTrees, numEdges, numEtt, numCorns, numCtt));
15910a96aa3bSJed Brown   #else
1592792fecdfSBarry Smith   PetscCallP4estReturn(conn, p4est_connectivity_new, (numVerts, numTrees, numCorns, numCtt));
15930a96aa3bSJed Brown   #endif
15940a96aa3bSJed Brown 
15950a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
15969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 1, &fStart, &fEnd));
15979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((cEnd - cStart) * P4EST_FACES, &ttf));
15980a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
15990a96aa3bSJed Brown     PetscInt        numSupp, s;
16000a96aa3bSJed Brown     PetscInt        myFace[2] = {-1, -1};
16010a96aa3bSJed Brown     PetscInt        myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
16020a96aa3bSJed Brown     const PetscInt *supp;
16030a96aa3bSJed Brown 
16049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numSupp));
16051dca8a05SBarry 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);
16069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &supp));
16070a96aa3bSJed Brown 
16080a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16090a96aa3bSJed Brown       PetscInt p = supp[s];
16100a96aa3bSJed Brown 
16110a96aa3bSJed Brown       if (p >= cEnd) {
16120a96aa3bSJed Brown         numSupp--;
16130a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
16140a96aa3bSJed Brown         break;
16150a96aa3bSJed Brown       }
16160a96aa3bSJed Brown     }
16170a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16180a96aa3bSJed Brown       PetscInt        p = supp[s], i;
16190a96aa3bSJed Brown       PetscInt        numCone;
16200a96aa3bSJed Brown       DMPolytopeType  ct;
16210a96aa3bSJed Brown       const PetscInt *cone;
16220a96aa3bSJed Brown       const PetscInt *ornt;
16230a96aa3bSJed Brown       PetscInt        orient = PETSC_MIN_INT;
16240a96aa3bSJed Brown 
16259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &numCone));
162663a3b9bcSJacob 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);
16279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
16289566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[0], &ct));
16299566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
16300a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
16310a96aa3bSJed Brown         if (cone[i] == f) {
16320a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
16330a96aa3bSJed Brown           break;
16340a96aa3bSJed Brown         }
16350a96aa3bSJed Brown       }
163663a3b9bcSJacob Faibussowitsch       PetscCheck(i < P4EST_FACES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "cell %" PetscInt_FMT " faced %" PetscInt_FMT " mismatch", p, f);
16370a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
16380a96aa3bSJed Brown         DMPolytopeType ct;
16399566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
164063a3b9bcSJacob 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);
16410a96aa3bSJed Brown       }
16420a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
16430a96aa3bSJed Brown       if (numSupp == 1) {
16440a96aa3bSJed Brown         /* boundary faces indicated by self reference */
16450a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
16460a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t)PetscFaceToP4estFace[i];
16470a96aa3bSJed Brown       } else {
16480a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16490a96aa3bSJed Brown 
16500a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
16510a96aa3bSJed Brown         myFace[s]                                                                = PetscFaceToP4estFace[i];
16520a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
16530a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
16540a96aa3bSJed Brown         myOrnt[s] = DihedralCompose(N, orient, DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
16550a96aa3bSJed Brown       }
16560a96aa3bSJed Brown     }
16570a96aa3bSJed Brown     if (numSupp == 2) {
16580a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
16590a96aa3bSJed Brown         PetscInt       p = supp[s];
16600a96aa3bSJed Brown         PetscInt       orntAtoB;
16610a96aa3bSJed Brown         PetscInt       p4estOrient;
16620a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16630a96aa3bSJed Brown 
16640a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
16650a96aa3bSJed Brown          * permutation of this cell-facet's cone */
16660a96aa3bSJed Brown         orntAtoB = DihedralCompose(N, DihedralInvert(N, myOrnt[1 - s]), myOrnt[s]);
16670a96aa3bSJed Brown 
16680a96aa3bSJed Brown         /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
16690a96aa3bSJed Brown          * vertices around facet) */
16700a96aa3bSJed Brown   #if !defined(P4_TO_P8)
16710a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
16720a96aa3bSJed Brown   #else
16730a96aa3bSJed Brown         {
16740a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
16750a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
16760a96aa3bSJed Brown 
16770a96aa3bSJed Brown           /* swap bits */
16780a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
16790a96aa3bSJed Brown         }
16800a96aa3bSJed Brown   #endif
16810a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
16820a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
16830a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t)myFace[1 - s] + p4estOrient * P4EST_FACES;
16840a96aa3bSJed Brown       }
16850a96aa3bSJed Brown     }
16860a96aa3bSJed Brown   }
16870a96aa3bSJed Brown 
16880a96aa3bSJed Brown   #if defined(P4_TO_P8)
16890a96aa3bSJed Brown   /* 3: visit every edge */
16900a96aa3bSJed Brown   conn->ett_offset[0] = 0;
16910a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
16920a96aa3bSJed Brown     PetscInt off, s;
16930a96aa3bSJed Brown 
16949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ett, e, &off));
16950a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t)off;
16969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
16970a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
16980a96aa3bSJed Brown       PetscInt p = star[2 * s];
16990a96aa3bSJed Brown 
17000a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17019566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
170208401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure");
17030a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
17040a96aa3bSJed Brown           PetscInt       cellEdge = closure[2 * (c + edgeOff)];
17050a96aa3bSJed Brown           PetscInt       cellOrnt = closure[2 * (c + edgeOff) + 1];
17060a96aa3bSJed Brown           DMPolytopeType ct;
17070a96aa3bSJed Brown 
17089566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cellEdge, &ct));
17090a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
17100a96aa3bSJed Brown           if (cellEdge == e) {
17110a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
17120a96aa3bSJed Brown             PetscInt totalOrient;
17130a96aa3bSJed Brown 
17140a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
17150a96aa3bSJed Brown             totalOrient = DihedralCompose(2, cellOrnt, DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
17160a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
17170a96aa3bSJed Brown             totalOrient             = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
17180a96aa3bSJed Brown             conn->edge_to_tree[off] = (p4est_locidx_t)(p - cStart);
1719d5b43468SJose E. Roman             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standard (see
17200a96aa3bSJed Brown              * p8est_connectivity.h) */
17210a96aa3bSJed Brown             conn->edge_to_edge[off++]                                  = (int8_t)p4estEdge + P8EST_EDGES * totalOrient;
17220a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
17230a96aa3bSJed Brown           }
17240a96aa3bSJed Brown         }
17259566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
17260a96aa3bSJed Brown       }
17270a96aa3bSJed Brown     }
17289566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
17290a96aa3bSJed Brown   }
17309566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ett));
17310a96aa3bSJed Brown   #endif
17320a96aa3bSJed Brown 
17330a96aa3bSJed Brown   /* 4: visit every vertex */
17340a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
17350a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
17360a96aa3bSJed Brown     PetscInt off, s;
17370a96aa3bSJed Brown 
17389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ctt, v, &off));
17390a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t)off;
17409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
17410a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17420a96aa3bSJed Brown       PetscInt p = star[2 * s];
17430a96aa3bSJed Brown 
17440a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17459566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
174608401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure");
17470a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
17480a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
17490a96aa3bSJed Brown 
17500a96aa3bSJed Brown           if (cellVert == v) {
17510a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
17520a96aa3bSJed Brown 
17530a96aa3bSJed Brown             conn->corner_to_tree[off]                                       = (p4est_locidx_t)(p - cStart);
17540a96aa3bSJed Brown             conn->corner_to_corner[off++]                                   = (int8_t)p4estVert;
17550a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
17560a96aa3bSJed Brown           }
17570a96aa3bSJed Brown         }
17589566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
17590a96aa3bSJed Brown       }
17600a96aa3bSJed Brown     }
17619566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
17620a96aa3bSJed Brown   }
17639566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ctt));
17640a96aa3bSJed Brown 
17650a96aa3bSJed Brown   /* 5: Compute the coordinates */
17660a96aa3bSJed Brown   {
17670a96aa3bSJed Brown     PetscInt coordDim;
17680a96aa3bSJed Brown 
17699566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
17706858538eSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocalSetUp(dm));
17710a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
17720a96aa3bSJed Brown       PetscInt           dof;
17736858538eSMatthew G. Knepley       PetscBool          isDG;
17740a96aa3bSJed Brown       PetscScalar       *cellCoords = NULL;
17756858538eSMatthew G. Knepley       const PetscScalar *array;
17760a96aa3bSJed Brown 
17776858538eSMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17786858538eSMatthew 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);
17790a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
17800a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
17810a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
17820a96aa3bSJed Brown 
17830a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
17840a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
17850a96aa3bSJed Brown         for (i = 0; i < 3; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
17860a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
17870a96aa3bSJed Brown       }
17886858538eSMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17890a96aa3bSJed Brown     }
17900a96aa3bSJed Brown   }
17910a96aa3bSJed Brown 
17920a96aa3bSJed Brown   #if defined(P4EST_ENABLE_DEBUG)
179308401ef6SPierre Jolivet   PetscCheck(p4est_connectivity_is_valid(conn), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Plex to p4est conversion failed");
17940a96aa3bSJed Brown   #endif
17950a96aa3bSJed Brown 
17960a96aa3bSJed Brown   *connOut = conn;
17970a96aa3bSJed Brown 
17980a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
17990a96aa3bSJed Brown 
18003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18010a96aa3bSJed Brown }
18020a96aa3bSJed Brown 
1803d71ae5a4SJacob Faibussowitsch static PetscErrorCode locidx_to_PetscInt(sc_array_t *array)
1804d71ae5a4SJacob Faibussowitsch {
18050a96aa3bSJed Brown   sc_array_t *newarray;
18060a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18070a96aa3bSJed Brown 
18080a96aa3bSJed Brown   PetscFunctionBegin;
180908401ef6SPierre Jolivet   PetscCheck(array->elem_size == sizeof(p4est_locidx_t), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong locidx size");
18100a96aa3bSJed Brown 
18113ba16761SJacob Faibussowitsch   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(PETSC_SUCCESS);
18120a96aa3bSJed Brown 
18130a96aa3bSJed Brown   newarray = sc_array_new_size(sizeof(PetscInt), array->elem_count);
18140a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18150a96aa3bSJed Brown     p4est_locidx_t il = *((p4est_locidx_t *)sc_array_index(array, zz));
18160a96aa3bSJed Brown     PetscInt      *ip = (PetscInt *)sc_array_index(newarray, zz);
18170a96aa3bSJed Brown 
18180a96aa3bSJed Brown     *ip = (PetscInt)il;
18190a96aa3bSJed Brown   }
18200a96aa3bSJed Brown 
18210a96aa3bSJed Brown   sc_array_reset(array);
18220a96aa3bSJed Brown   sc_array_init_size(array, sizeof(PetscInt), count);
18230a96aa3bSJed Brown   sc_array_copy(array, newarray);
18240a96aa3bSJed Brown   sc_array_destroy(newarray);
18253ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18260a96aa3bSJed Brown }
18270a96aa3bSJed Brown 
1828d71ae5a4SJacob Faibussowitsch static PetscErrorCode coords_double_to_PetscScalar(sc_array_t *array, PetscInt dim)
1829d71ae5a4SJacob Faibussowitsch {
18300a96aa3bSJed Brown   sc_array_t *newarray;
18310a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18320a96aa3bSJed Brown 
18330a96aa3bSJed Brown   PetscFunctionBegin;
18341dca8a05SBarry Smith   PetscCheck(array->elem_size == 3 * sizeof(double), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong coordinate size");
18350a96aa3bSJed Brown   #if !defined(PETSC_USE_COMPLEX)
18363ba16761SJacob Faibussowitsch   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(PETSC_SUCCESS);
18370a96aa3bSJed Brown   #endif
18380a96aa3bSJed Brown 
18390a96aa3bSJed Brown   newarray = sc_array_new_size(dim * sizeof(PetscScalar), array->elem_count);
18400a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18410a96aa3bSJed Brown     int          i;
18420a96aa3bSJed Brown     double      *id = (double *)sc_array_index(array, zz);
18430a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar *)sc_array_index(newarray, zz);
18440a96aa3bSJed Brown 
18450a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
18460a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim, 3); i++) ip[i] = (PetscScalar)id[i];
18470a96aa3bSJed Brown   }
18480a96aa3bSJed Brown 
18490a96aa3bSJed Brown   sc_array_reset(array);
18500a96aa3bSJed Brown   sc_array_init_size(array, dim * sizeof(PetscScalar), count);
18510a96aa3bSJed Brown   sc_array_copy(array, newarray);
18520a96aa3bSJed Brown   sc_array_destroy(newarray);
18533ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18540a96aa3bSJed Brown }
18550a96aa3bSJed Brown 
1856d71ae5a4SJacob Faibussowitsch static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t *array)
1857d71ae5a4SJacob Faibussowitsch {
18580a96aa3bSJed Brown   sc_array_t *newarray;
18590a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18600a96aa3bSJed Brown 
18610a96aa3bSJed Brown   PetscFunctionBegin;
18621dca8a05SBarry Smith   PetscCheck(array->elem_size == 2 * sizeof(p4est_locidx_t), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong locidx size");
18630a96aa3bSJed Brown 
18640a96aa3bSJed Brown   newarray = sc_array_new_size(sizeof(PetscSFNode), array->elem_count);
18650a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18660a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t *)sc_array_index(array, zz);
18670a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode *)sc_array_index(newarray, zz);
18680a96aa3bSJed Brown 
18690a96aa3bSJed Brown     ip->rank  = (PetscInt)il[0];
18700a96aa3bSJed Brown     ip->index = (PetscInt)il[1];
18710a96aa3bSJed Brown   }
18720a96aa3bSJed Brown 
18730a96aa3bSJed Brown   sc_array_reset(array);
18740a96aa3bSJed Brown   sc_array_init_size(array, sizeof(PetscSFNode), count);
18750a96aa3bSJed Brown   sc_array_copy(array, newarray);
18760a96aa3bSJed Brown   sc_array_destroy(newarray);
18773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18780a96aa3bSJed Brown }
18790a96aa3bSJed Brown 
1880d71ae5a4SJacob Faibussowitsch static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM *plex)
1881d71ae5a4SJacob Faibussowitsch {
18820a96aa3bSJed Brown   PetscFunctionBegin;
18830a96aa3bSJed Brown   {
18840a96aa3bSJed Brown     sc_array_t    *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
18850a96aa3bSJed Brown     sc_array_t    *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
18860a96aa3bSJed Brown     sc_array_t    *cones             = sc_array_new(sizeof(p4est_locidx_t));
18870a96aa3bSJed Brown     sc_array_t    *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
18880a96aa3bSJed Brown     sc_array_t    *coords            = sc_array_new(3 * sizeof(double));
18890a96aa3bSJed Brown     sc_array_t    *children          = sc_array_new(sizeof(p4est_locidx_t));
18900a96aa3bSJed Brown     sc_array_t    *parents           = sc_array_new(sizeof(p4est_locidx_t));
18910a96aa3bSJed Brown     sc_array_t    *childids          = sc_array_new(sizeof(p4est_locidx_t));
18920a96aa3bSJed Brown     sc_array_t    *leaves            = sc_array_new(sizeof(p4est_locidx_t));
18930a96aa3bSJed Brown     sc_array_t    *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
18940a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
18950a96aa3bSJed Brown 
1896792fecdfSBarry 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));
18970a96aa3bSJed Brown 
18989566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
18999566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
19009566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
19019566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
19029566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, P4EST_DIM));
19030a96aa3bSJed Brown 
19049566063dSJacob Faibussowitsch     PetscCall(DMPlexCreate(PETSC_COMM_SELF, plex));
19059566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(*plex, P4EST_DIM));
19069566063dSJacob 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));
19079566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(*plex));
19080a96aa3bSJed Brown     sc_array_destroy(points_per_dim);
19090a96aa3bSJed Brown     sc_array_destroy(cone_sizes);
19100a96aa3bSJed Brown     sc_array_destroy(cones);
19110a96aa3bSJed Brown     sc_array_destroy(cone_orientations);
19120a96aa3bSJed Brown     sc_array_destroy(coords);
19130a96aa3bSJed Brown     sc_array_destroy(children);
19140a96aa3bSJed Brown     sc_array_destroy(parents);
19150a96aa3bSJed Brown     sc_array_destroy(childids);
19160a96aa3bSJed Brown     sc_array_destroy(leaves);
19170a96aa3bSJed Brown     sc_array_destroy(remotes);
19180a96aa3bSJed Brown   }
19193ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19200a96aa3bSJed Brown }
19210a96aa3bSJed Brown 
19220a96aa3bSJed Brown   #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
1923d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
1924d71ae5a4SJacob Faibussowitsch {
19250a96aa3bSJed Brown   PetscInt coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
19260a96aa3bSJed Brown 
19270a96aa3bSJed Brown   PetscFunctionBegin;
19280a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
19290a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
19300a96aa3bSJed Brown     if (childB) *childB = childA;
19313ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19320a96aa3bSJed Brown   }
19339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
19346aad120cSJose E. Roman   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invariant under rotation */
19350a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
19360a96aa3bSJed Brown     if (childB) *childB = childA;
19373ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19380a96aa3bSJed Brown   }
19390a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
19409566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
19410a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
19420a96aa3bSJed Brown   }
194363a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
194428b400f6SJacob Faibussowitsch   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
19450a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
19460a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
19470a96aa3bSJed Brown     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
19480a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
19490a96aa3bSJed Brown 
19509566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
19519566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, childA, &supp));
19520a96aa3bSJed Brown 
19530a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
19540a96aa3bSJed Brown     for (i = 0; i < size; i++) {
19550a96aa3bSJed Brown       PetscInt sParent;
19560a96aa3bSJed Brown 
19570a96aa3bSJed Brown       sA = supp[i];
19580a96aa3bSJed Brown       if (sA == parent) continue;
19599566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
19600a96aa3bSJed Brown       if (sParent == parent) break;
19610a96aa3bSJed Brown     }
196208401ef6SPierre Jolivet     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
19630a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
19640a96aa3bSJed Brown      * parentOrientB */
19659566063dSJacob Faibussowitsch     PetscCall(DMReferenceTreeGetChildSymmetry_pforest(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
19669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
19679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sA, &coneA));
19689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sB, &coneB));
19699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
19709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
19710a96aa3bSJed Brown     /* step through the cone of sA in natural order */
19720a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
19730a96aa3bSJed Brown       if (coneA[i] == childA) {
19740a96aa3bSJed Brown         /* if childA is at position i in coneA,
19750a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
19760a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
19770a96aa3bSJed Brown         if (childB) *childB = coneB[j];
19780a96aa3bSJed Brown         if (childOrientB) {
19790a96aa3bSJed Brown           DMPolytopeType ct;
19800a96aa3bSJed Brown           PetscInt       oBtrue;
19810a96aa3bSJed Brown 
19829566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
19830a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
19841dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
19850a96aa3bSJed Brown           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
19860a96aa3bSJed Brown           /* we may have to flip an edge */
19870a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
19880a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
19890a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
19900a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
19910a96aa3bSJed Brown         }
19920a96aa3bSJed Brown         break;
19930a96aa3bSJed Brown       }
19940a96aa3bSJed Brown     }
199508401ef6SPierre Jolivet     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
19963ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19970a96aa3bSJed Brown   }
19980a96aa3bSJed Brown   /* get the cone size and symmetry swap */
19999566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
20000a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
20010a96aa3bSJed Brown   if (dim == 2) {
20020a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
20030a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
20040a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
20050a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
20060a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
20070a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
20080a96aa3bSJed Brown   } else {
20090a96aa3bSJed Brown     oAvert     = parentOrientA;
20100a96aa3bSJed Brown     oBvert     = parentOrientB;
20110a96aa3bSJed Brown     ABswapVert = ABswap;
20120a96aa3bSJed Brown   }
20130a96aa3bSJed Brown   if (childB) {
20140a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
20150a96aa3bSJed Brown     PetscInt        p, posA = -1, numChildren, i;
20160a96aa3bSJed Brown     const PetscInt *children;
20170a96aa3bSJed Brown 
20180a96aa3bSJed Brown     /* count which position the child is in */
20199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
20200a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
20210a96aa3bSJed Brown       p = children[i];
20220a96aa3bSJed Brown       if (p == childA) {
20230a96aa3bSJed Brown         if (dim == 1) {
20240a96aa3bSJed Brown           posA = i;
20250a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
20260a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
20270a96aa3bSJed Brown         }
20280a96aa3bSJed Brown         break;
20290a96aa3bSJed Brown       }
20300a96aa3bSJed Brown     }
20310a96aa3bSJed Brown     if (posA >= coneSize) {
20320a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find childA in children of parent");
20330a96aa3bSJed Brown     } else {
20340a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
20350a96aa3bSJed Brown       PetscInt posB, childIdB;
20360a96aa3bSJed Brown 
20370a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
20380a96aa3bSJed Brown       if (dim == 1) {
20390a96aa3bSJed Brown         childIdB = posB;
20400a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
20410a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
20420a96aa3bSJed Brown       }
20430a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
20440a96aa3bSJed Brown     }
20450a96aa3bSJed Brown   }
20460a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
20473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20480a96aa3bSJed Brown }
20490a96aa3bSJed Brown 
20500a96aa3bSJed Brown   #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
2051d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm)
2052d71ae5a4SJacob Faibussowitsch {
20530a96aa3bSJed Brown   p4est_connectivity_t *refcube;
20540a96aa3bSJed Brown   p4est_t              *root, *refined;
20550a96aa3bSJed Brown   DM                    dmRoot, dmRefined;
20560a96aa3bSJed Brown   DM_Plex              *mesh;
20570a96aa3bSJed Brown   PetscMPIInt           rank;
205866c0a4b5SToby Isaac   #if defined(PETSC_HAVE_MPIUNI)
205966c0a4b5SToby Isaac   sc_MPI_Comm comm_self = sc_MPI_COMM_SELF;
206066c0a4b5SToby Isaac   #else
206166c0a4b5SToby Isaac   MPI_Comm comm_self = PETSC_COMM_SELF;
206266c0a4b5SToby Isaac   #endif
20630a96aa3bSJed Brown 
20640a96aa3bSJed Brown   PetscFunctionBegin;
2065792fecdfSBarry Smith   PetscCallP4estReturn(refcube, p4est_connectivity_new_byname, ("unit"));
20660a96aa3bSJed Brown   { /* [-1,1]^d geometry */
20670a96aa3bSJed Brown     PetscInt i, j;
20680a96aa3bSJed Brown 
20690a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
20700a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
20710a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
20720a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
20730a96aa3bSJed Brown       }
20740a96aa3bSJed Brown     }
20750a96aa3bSJed Brown   }
2076792fecdfSBarry Smith   PetscCallP4estReturn(root, p4est_new, (comm_self, refcube, 0, NULL, NULL));
2077792fecdfSBarry Smith   PetscCallP4estReturn(refined, p4est_new_ext, (comm_self, refcube, 0, 1, 1, 0, NULL, NULL));
20789566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(root, &dmRoot));
20799566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(refined, &dmRefined));
20800a96aa3bSJed Brown   {
20810a96aa3bSJed Brown   #if !defined(P4_TO_P8)
20820a96aa3bSJed Brown     PetscInt nPoints   = 25;
20839371c9d4SSatish 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};
20849371c9d4SSatish 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};
20850a96aa3bSJed Brown   #else
20860a96aa3bSJed Brown     PetscInt nPoints    = 125;
20879371c9d4SSatish 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,
20889371c9d4SSatish 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,
20899371c9d4SSatish 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};
20909371c9d4SSatish 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,
20919371c9d4SSatish 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};
20920a96aa3bSJed Brown 
20930a96aa3bSJed Brown   #endif
20940a96aa3bSJed Brown     IS permIS;
20950a96aa3bSJed Brown     DM dmPerm;
20960a96aa3bSJed Brown 
20979566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nPoints, perm, PETSC_USE_POINTER, &permIS));
20989566063dSJacob Faibussowitsch     PetscCall(DMPlexPermute(dmRefined, permIS, &dmPerm));
20990a96aa3bSJed Brown     if (dmPerm) {
21009566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmRefined));
21010a96aa3bSJed Brown       dmRefined = dmPerm;
21020a96aa3bSJed Brown     }
21039566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
21040a96aa3bSJed Brown     {
21050a96aa3bSJed Brown       PetscInt p;
21069566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRoot, "identity"));
21079566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRefined, "identity"));
210848a46eb9SPierre Jolivet       for (p = 0; p < P4EST_INSUL; p++) PetscCall(DMSetLabelValue(dmRoot, "identity", p, p));
210948a46eb9SPierre Jolivet       for (p = 0; p < nPoints; p++) PetscCall(DMSetLabelValue(dmRefined, "identity", p, ident[p]));
21100a96aa3bSJed Brown     }
21110a96aa3bSJed Brown   }
21129566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(dmRoot, dmRefined, "identity", dm));
21130a96aa3bSJed Brown   mesh                   = (DM_Plex *)(*dm)->data;
21140a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
21159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
21160a96aa3bSJed Brown   if (rank == 0) {
21179566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRoot, NULL, "-dm_p4est_ref_root_view"));
21189566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined, NULL, "-dm_p4est_ref_refined_view"));
21199566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined, NULL, "-dm_p4est_ref_tree_view"));
21200a96aa3bSJed Brown   }
21219566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRefined));
21229566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRoot));
2123792fecdfSBarry Smith   PetscCallP4est(p4est_destroy, (refined));
2124792fecdfSBarry Smith   PetscCallP4est(p4est_destroy, (root));
2125792fecdfSBarry Smith   PetscCallP4est(p4est_connectivity_destroy, (refcube));
21263ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21270a96aa3bSJed Brown }
21280a96aa3bSJed Brown 
2129d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB)
2130d71ae5a4SJacob Faibussowitsch {
21310a96aa3bSJed Brown   void     *ctx;
21320a96aa3bSJed Brown   PetscInt  num;
21330a96aa3bSJed Brown   PetscReal val;
21340a96aa3bSJed Brown 
21350a96aa3bSJed Brown   PetscFunctionBegin;
21369566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmA, &ctx));
21379566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dmB, ctx));
21389566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmA, dmB));
21399566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dmA, &num, &val));
21409566063dSJacob Faibussowitsch   PetscCall(DMSetOutputSequenceNumber(dmB, num, val));
21410a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
21429566063dSJacob Faibussowitsch     PetscCall(DMClearLocalVectors(dmB));
21439566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->localSection));
21449566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->localSection)));
21450a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
21469566063dSJacob Faibussowitsch     PetscCall(DMClearGlobalVectors(dmB));
21479566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->globalSection));
21489566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->globalSection)));
21490a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
21509566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.section));
21519566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->defaultConstraint.section)));
21523b8ba7d1SJed Brown     dmB->defaultConstraint.section = dmA->defaultConstraint.section;
21539566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.mat));
21549566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(dmB->defaultConstraint.mat)));
21553b8ba7d1SJed Brown     dmB->defaultConstraint.mat = dmA->defaultConstraint.mat;
21569566063dSJacob Faibussowitsch     if (dmA->map) PetscCall(PetscLayoutReference(dmA->map, &dmB->map));
21570a96aa3bSJed Brown   }
21580a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
21599566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->sectionSF));
21609566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&dmB->sectionSF));
21610a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
21620a96aa3bSJed Brown   }
21633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21640a96aa3bSJed Brown }
21650a96aa3bSJed Brown 
21660a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
2167d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm, p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF)
2168d71ae5a4SJacob Faibussowitsch {
21690a96aa3bSJed Brown   PetscInt     startF, endF, startC, endC, p, nLeaves;
21700a96aa3bSJed Brown   PetscSFNode *leaves;
21710a96aa3bSJed Brown   PetscSF      sf;
21720a96aa3bSJed Brown   PetscInt    *recv, *send;
21730a96aa3bSJed Brown   PetscMPIInt  tag;
21740a96aa3bSJed Brown   MPI_Request *recvReqs, *sendReqs;
21750a96aa3bSJed Brown   PetscSection section;
21760a96aa3bSJed Brown 
21770a96aa3bSJed Brown   PetscFunctionBegin;
21789566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize, p4estC->mpirank, p4estF, p4estC, &startC, &endC));
21799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2 * (endC - startC), &recv, endC - startC, &recvReqs));
21809566063dSJacob Faibussowitsch   PetscCall(PetscCommGetNewTag(comm, &tag));
21810a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
21820a96aa3bSJed Brown     recvReqs[p - startC] = MPI_REQUEST_NULL;                                        /* just in case we don't initiate a receive */
21830a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p + 1]) { /* empty coarse partition */
21840a96aa3bSJed Brown       recv[2 * (p - startC)]     = 0;
21850a96aa3bSJed Brown       recv[2 * (p - startC) + 1] = 0;
21860a96aa3bSJed Brown       continue;
21870a96aa3bSJed Brown     }
21880a96aa3bSJed Brown 
21899566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(&recv[2 * (p - startC)], 2, MPIU_INT, p, tag, comm, &recvReqs[p - startC]));
21900a96aa3bSJed Brown   }
21919566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize, p4estC->mpirank, p4estC, p4estF, &startF, &endF));
21929566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2 * (endF - startF), &send, endF - startF, &sendReqs));
21930a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
21940a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
21950a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
21960a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p + 1];
21970a96aa3bSJed Brown     PetscInt          tStart      = (PetscInt)myFineStart->p.which_tree;
21980a96aa3bSJed Brown     PetscInt          tEnd        = (PetscInt)myFineEnd->p.which_tree;
21990a96aa3bSJed Brown     PetscInt          firstCell = -1, lastCell = -1;
22000a96aa3bSJed Brown     p4est_tree_t     *treeStart = &(((p4est_tree_t *)p4estC->trees->array)[tStart]);
22010a96aa3bSJed Brown     p4est_tree_t     *treeEnd   = (size_t)tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t *)p4estC->trees->array)[tEnd]) : NULL;
22020a96aa3bSJed Brown     ssize_t           overlapIndex;
22030a96aa3bSJed Brown 
22040a96aa3bSJed Brown     sendReqs[p - startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
22050a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p + 1]) continue;
22060a96aa3bSJed Brown 
22070a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
22080a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
2209792fecdfSBarry Smith       PetscCallP4estReturn(overlapIndex, sc_array_bsearch, (&(treeStart->quadrants), myFineStart, p4est_quadrant_disjoint));
22100a96aa3bSJed Brown       if (overlapIndex < 0) {
22110a96aa3bSJed Brown         firstCell = 0;
22120a96aa3bSJed Brown       } else {
22130a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
22140a96aa3bSJed Brown       }
22150a96aa3bSJed Brown     } else {
22160a96aa3bSJed Brown       firstCell = 0;
22170a96aa3bSJed Brown     }
22180a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
2219792fecdfSBarry Smith       PetscCallP4estReturn(overlapIndex, sc_array_bsearch, (&(treeEnd->quadrants), myFineEnd, p4est_quadrant_disjoint));
22200a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
22210a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
22220a96aa3bSJed Brown       } else {
22230a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t *)treeEnd->quadrants.array)[overlapIndex]);
22240a96aa3bSJed Brown         p4est_quadrant_t  first_desc;
22250a96aa3bSJed Brown         int               equal;
22260a96aa3bSJed Brown 
2227792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_first_descendant, (container, &first_desc, P4EST_QMAXLEVEL));
2228792fecdfSBarry Smith         PetscCallP4estReturn(equal, p4est_quadrant_is_equal, (myFineEnd, &first_desc));
22290a96aa3bSJed Brown         if (equal) {
22300a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
22310a96aa3bSJed Brown         } else {
22320a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
22330a96aa3bSJed Brown         }
22340a96aa3bSJed Brown       }
22350a96aa3bSJed Brown     } else {
22360a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
22370a96aa3bSJed Brown     }
22380a96aa3bSJed Brown     send[2 * (p - startF)]     = firstCell;
22390a96aa3bSJed Brown     send[2 * (p - startF) + 1] = lastCell - firstCell;
22409566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(&send[2 * (p - startF)], 2, MPIU_INT, p, tag, comm, &sendReqs[p - startF]));
22410a96aa3bSJed Brown   }
22429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endC - startC), recvReqs, MPI_STATUSES_IGNORE));
22439566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
22449566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, startC, endC));
22450a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22460a96aa3bSJed Brown     PetscInt numCells = recv[2 * (p - startC) + 1];
22479566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section, p, numCells));
22480a96aa3bSJed Brown   }
22499566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
22509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &nLeaves));
22519566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nLeaves, &leaves));
22520a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22530a96aa3bSJed Brown     PetscInt firstCell = recv[2 * (p - startC)];
22540a96aa3bSJed Brown     PetscInt numCells  = recv[2 * (p - startC) + 1];
22550a96aa3bSJed Brown     PetscInt off, i;
22560a96aa3bSJed Brown 
22579566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
22580a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
22590a96aa3bSJed Brown       leaves[off + i].rank  = p;
22600a96aa3bSJed Brown       leaves[off + i].index = firstCell + i;
22610a96aa3bSJed Brown     }
22620a96aa3bSJed Brown   }
22639566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf));
22649566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, cEnd - cStart, nLeaves, NULL, PETSC_OWN_POINTER, leaves, PETSC_OWN_POINTER));
22659566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
22669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endF - startF), sendReqs, MPI_STATUSES_IGNORE));
22679566063dSJacob Faibussowitsch   PetscCall(PetscFree2(send, sendReqs));
22689566063dSJacob Faibussowitsch   PetscCall(PetscFree2(recv, recvReqs));
22690a96aa3bSJed Brown   *coveringSF = sf;
22703ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22710a96aa3bSJed Brown }
22720a96aa3bSJed Brown 
22730a96aa3bSJed Brown /* closure points for locally-owned cells */
2274d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints, PetscBool redirect)
2275d71ae5a4SJacob Faibussowitsch {
22760a96aa3bSJed Brown   PetscInt           cStart, cEnd;
22770a96aa3bSJed Brown   PetscInt           count, c;
22780a96aa3bSJed Brown   PetscMPIInt        rank;
22790a96aa3bSJed Brown   PetscInt           closureSize = -1;
22800a96aa3bSJed Brown   PetscInt          *closure     = NULL;
22810a96aa3bSJed Brown   PetscSF            pointSF;
22820a96aa3bSJed Brown   PetscInt           nleaves, nroots;
22830a96aa3bSJed Brown   const PetscInt    *ilocal;
22840a96aa3bSJed Brown   const PetscSFNode *iremote;
22850a96aa3bSJed Brown   DM                 plex;
22860a96aa3bSJed Brown   DM_Forest         *forest;
22870a96aa3bSJed Brown   DM_Forest_pforest *pforest;
22880a96aa3bSJed Brown 
22890a96aa3bSJed Brown   PetscFunctionBegin;
22900a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
22910a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
22920a96aa3bSJed Brown   cStart  = pforest->cLocalStart;
22930a96aa3bSJed Brown   cEnd    = pforest->cLocalEnd;
22949566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
22959566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &pointSF));
22969566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &ilocal, &iremote));
22970a96aa3bSJed Brown   nleaves           = PetscMax(0, nleaves);
22980a96aa3bSJed Brown   nroots            = PetscMax(0, nroots);
22990a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
23009566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numClosurePoints, closurePoints));
23019566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
23020a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
23030a96aa3bSJed Brown     PetscInt i;
23049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(plex, c, PETSC_TRUE, &closureSize, &closure));
23050a96aa3bSJed Brown 
23060a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
23070a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
23080a96aa3bSJed Brown       PetscInt loc = -1;
23090a96aa3bSJed Brown 
23109566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(p, nleaves, ilocal, &loc));
23110a96aa3bSJed Brown       if (redirect && loc >= 0) {
23120a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
23130a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
23140a96aa3bSJed Brown       } else {
23150a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
23160a96aa3bSJed Brown         (*closurePoints)[count].index = p;
23170a96aa3bSJed Brown       }
23180a96aa3bSJed Brown     }
23199566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(plex, c, PETSC_TRUE, &closureSize, &closure));
23200a96aa3bSJed Brown   }
23213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23220a96aa3bSJed Brown }
23230a96aa3bSJed Brown 
2324d71ae5a4SJacob Faibussowitsch static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type)
2325d71ae5a4SJacob Faibussowitsch {
23260a96aa3bSJed Brown   PetscMPIInt i;
23270a96aa3bSJed Brown 
23280a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
23290a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode *)a;
23300a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode *)b;
23310a96aa3bSJed Brown 
23320a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
23330a96aa3bSJed Brown   }
23340a96aa3bSJed Brown }
23350a96aa3bSJed Brown 
2336d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
2337d71ae5a4SJacob Faibussowitsch {
23380a96aa3bSJed Brown   MPI_Comm           comm;
23390a96aa3bSJed Brown   PetscMPIInt        rank, size;
23400a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
23410a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
23420a96aa3bSJed Brown   PetscInt           numClosureIndices;
23430a96aa3bSJed Brown   PetscInt           numClosurePointsC, numClosurePointsF;
23440a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
23450a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
23460a96aa3bSJed Brown   p4est_quadrant_t **treeQuads;
23470a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
23480a96aa3bSJed Brown   MPI_Datatype       nodeType;
23490a96aa3bSJed Brown   MPI_Datatype       nodeClosureType;
23500a96aa3bSJed Brown   MPI_Op             sfNodeReduce;
23510a96aa3bSJed Brown   p4est_topidx_t     fltF, lltF, t;
23520a96aa3bSJed Brown   DM                 plexC, plexF;
23530a96aa3bSJed Brown   PetscInt           pStartF, pEndF, pStartC, pEndC;
23540a96aa3bSJed Brown   PetscBool          saveInCoarse = PETSC_FALSE;
23550a96aa3bSJed Brown   PetscBool          saveInFine   = PETSC_FALSE;
23560a96aa3bSJed Brown   PetscBool          formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
23570a96aa3bSJed Brown   PetscInt          *cids         = NULL;
23580a96aa3bSJed Brown 
23590a96aa3bSJed Brown   PetscFunctionBegin;
23600a96aa3bSJed Brown   pforestC = (DM_Forest_pforest *)((DM_Forest *)coarse->data)->data;
23610a96aa3bSJed Brown   pforestF = (DM_Forest_pforest *)((DM_Forest *)fine->data)->data;
23620a96aa3bSJed Brown   p4estC   = pforestC->forest;
23630a96aa3bSJed Brown   p4estF   = pforestF->forest;
236408401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo, PetscObjectComm((PetscObject)coarse), PETSC_ERR_ARG_INCOMP, "DM's must have the same base DM");
23650a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
23669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
23679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
23689566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine, &plexF));
23699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF, &pStartF, &pEndF));
23709566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse, &plexC));
23719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC, &pStartC, &pEndC));
23720a96aa3bSJed Brown   { /* check if the results have been cached */
23730a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
23740a96aa3bSJed Brown 
23759566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(coarse, &adaptCoarse));
23769566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(fine, &adaptFine));
23770a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
23780a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
23799566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestC->pointSelfToAdaptSF)));
23800a96aa3bSJed Brown         *sf = pforestC->pointSelfToAdaptSF;
23810a96aa3bSJed Brown         if (childIds) {
23829566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
23839566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids, pforestC->pointSelfToAdaptCids, pEndF - pStartF));
23840a96aa3bSJed Brown           *childIds = cids;
23850a96aa3bSJed Brown         }
23863ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
23870a96aa3bSJed Brown       } else {
23880a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
23890a96aa3bSJed Brown         formCids     = PETSC_TRUE;
23900a96aa3bSJed Brown       }
23910a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
23920a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
23939566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestF->pointAdaptToSelfSF)));
23940a96aa3bSJed Brown         *sf = pforestF->pointAdaptToSelfSF;
23950a96aa3bSJed Brown         if (childIds) {
23969566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
23979566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids, pforestF->pointAdaptToSelfCids, pEndF - pStartF));
23980a96aa3bSJed Brown           *childIds = cids;
23990a96aa3bSJed Brown         }
24003ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
24010a96aa3bSJed Brown       } else {
24020a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
24030a96aa3bSJed Brown         formCids   = PETSC_TRUE;
24040a96aa3bSJed Brown       }
24050a96aa3bSJed Brown     }
24060a96aa3bSJed Brown   }
24070a96aa3bSJed Brown 
24080a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
24090a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
24100a96aa3bSJed Brown   /* create the datatype */
24119566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(2, MPIU_INT, &nodeType));
24129566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
24139566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_create(DMPforestMaxSFNode, PETSC_FALSE, &sfNodeReduce));
24149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(numClosureIndices * 2, MPIU_INT, &nodeClosureType));
24159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeClosureType));
24160a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
24170a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
24189566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(coarse, numClosureIndices, &numClosurePointsC, &closurePointsC, PETSC_TRUE));
24199566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(fine, numClosureIndices, &numClosurePointsF, &closurePointsF, PETSC_FALSE));
24200a96aa3bSJed Brown   /* create pointers for tree lists */
24210a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
24220a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
24239566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(lltF + 1 - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts));
24240a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
24250a96aa3bSJed Brown   if (size > 1) {
24260a96aa3bSJed Brown     PetscInt p;
24270a96aa3bSJed Brown 
24280a96aa3bSJed Brown     for (p = 0; p < size; p++) {
24290a96aa3bSJed Brown       int equal;
24300a96aa3bSJed Brown 
2431792fecdfSBarry Smith       PetscCallP4estReturn(equal, p4est_quadrant_is_equal_piggy, (&p4estC->global_first_position[p], &p4estF->global_first_position[p]));
24320a96aa3bSJed Brown       if (!equal) break;
24330a96aa3bSJed Brown     }
24340a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
24350a96aa3bSJed Brown       PetscInt          cStartC, cEndC;
24360a96aa3bSJed Brown       PetscSF           coveringSF;
24370a96aa3bSJed Brown       PetscInt          nleaves;
24380a96aa3bSJed Brown       PetscInt          count;
24390a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
24400a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
24410a96aa3bSJed Brown       p4est_topidx_t    fltC = p4estC->first_local_tree;
24420a96aa3bSJed Brown       p4est_topidx_t    lltC = p4estC->last_local_tree;
24430a96aa3bSJed Brown       p4est_topidx_t    t;
24440a96aa3bSJed Brown       PetscMPIInt       blockSizes[4]   = {P4EST_DIM, 2, 1, 1};
24459371c9d4SSatish 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)};
24460a96aa3bSJed Brown       MPI_Datatype      blockTypes[4]   = {MPI_INT32_T, MPI_INT8_T, MPI_INT16_T, MPI_INT32_T /* p.which_tree */};
24470a96aa3bSJed Brown       MPI_Datatype      quadStruct, quadType;
24480a96aa3bSJed Brown 
24499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC, 0, &cStartC, &cEndC));
24509566063dSJacob Faibussowitsch       PetscCall(DMPforestGetCellCoveringSF(comm, p4estC, p4estF, pforestC->cLocalStart, pforestC->cLocalEnd, &coveringSF));
24519566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coveringSF, NULL, &nleaves, NULL, NULL));
24529566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numClosureIndices * nleaves, &newClosurePointsC));
24539566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &coverQuads));
24549566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cEndC - cStartC, &coverQuadsSend));
24550a96aa3bSJed Brown       count = 0;
24560a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
24570a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t *)p4estC->trees->array)[t]);
24580a96aa3bSJed Brown         PetscInt      q;
24590a96aa3bSJed Brown 
24609566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&coverQuadsSend[count], tree->quadrants.array, tree->quadrants.elem_count * sizeof(p4est_quadrant_t)));
24610a96aa3bSJed Brown         for (q = 0; (size_t)q < tree->quadrants.elem_count; q++) coverQuadsSend[count + q].p.which_tree = t;
24620a96aa3bSJed Brown         count += tree->quadrants.elem_count;
24630a96aa3bSJed Brown       }
24640a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
24650a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
24660a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
24670a96aa3bSJed Brown        */
24689566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_struct(4, blockSizes, blockOffsets, blockTypes, &quadStruct));
24699566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_resized(quadStruct, 0, sizeof(p4est_quadrant_t), &quadType));
24709566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&quadType));
24719566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF, nodeClosureType, closurePointsC, newClosurePointsC, MPI_REPLACE));
24729566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF, quadType, coverQuadsSend, coverQuads, MPI_REPLACE));
24739566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF, nodeClosureType, closurePointsC, newClosurePointsC, MPI_REPLACE));
24749566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF, quadType, coverQuadsSend, coverQuads, MPI_REPLACE));
24759566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadStruct));
24769566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadType));
24779566063dSJacob Faibussowitsch       PetscCall(PetscFree(coverQuadsSend));
24789566063dSJacob Faibussowitsch       PetscCall(PetscFree(closurePointsC));
24799566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coveringSF));
24800a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
24810a96aa3bSJed Brown 
24820a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
24830a96aa3bSJed Brown       {
24840a96aa3bSJed Brown         PetscInt q;
24850a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
24860a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
24870a96aa3bSJed Brown           if (!treeQuadCounts[t - fltF]++) treeQuads[t - fltF] = &coverQuads[q];
24880a96aa3bSJed Brown         }
24890a96aa3bSJed Brown       }
24900a96aa3bSJed Brown     }
24910a96aa3bSJed Brown   }
24920a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
24930a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
24940a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t *)p4estC->trees->array)[t]);
24950a96aa3bSJed Brown 
24960a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
24970a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t *)tree->quadrants.array;
24980a96aa3bSJed Brown     }
24990a96aa3bSJed Brown   }
25000a96aa3bSJed Brown 
25010a96aa3bSJed Brown   {
25020a96aa3bSJed Brown     PetscInt     p;
25030a96aa3bSJed Brown     PetscInt     cLocalStartF;
25040a96aa3bSJed Brown     PetscSF      pointSF;
25050a96aa3bSJed Brown     PetscSFNode *roots;
25060a96aa3bSJed Brown     PetscInt    *rootType;
25070a96aa3bSJed Brown     DM           refTree = NULL;
25080a96aa3bSJed Brown     DMLabel      canonical;
25090a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
25100a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
25110a96aa3bSJed Brown     PetscInt     coarseOffset;
25120a96aa3bSJed Brown     PetscInt     numCoarseQuads;
25130a96aa3bSJed Brown 
25149566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF - pStartF, &roots));
25159566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF - pStartF, &rootType));
25169566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(fine, &pointSF));
25170a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
25180a96aa3bSJed Brown       roots[p - pStartF].rank  = -1;
25190a96aa3bSJed Brown       roots[p - pStartF].index = -1;
25200a96aa3bSJed Brown       rootType[p - pStartF]    = -1;
25210a96aa3bSJed Brown     }
25220a96aa3bSJed Brown     if (formCids) {
25230a96aa3bSJed Brown       PetscInt child;
25240a96aa3bSJed Brown 
25259566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
25260a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
25279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF, &refTree));
25289566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(refTree, 0, PETSC_TRUE, NULL, &rootClosure));
25290a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
25309566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, child + 1, PETSC_TRUE, NULL, &childClosures[child]));
25310a96aa3bSJed Brown       }
25329566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(refTree, "canonical", &canonical));
25330a96aa3bSJed Brown     }
25340a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
25350a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
25360a96aa3bSJed Brown       p4est_tree_t     *tree         = &(((p4est_tree_t *)p4estF->trees->array)[t]);
25370a96aa3bSJed Brown       PetscInt          numFineQuads = tree->quadrants.elem_count;
25380a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads  = treeQuads[t - fltF];
25390a96aa3bSJed Brown       p4est_quadrant_t *fineQuads    = (p4est_quadrant_t *)tree->quadrants.array;
25400a96aa3bSJed Brown       PetscInt          i, coarseCount = 0;
25410a96aa3bSJed Brown       PetscInt          offset = tree->quadrants_offset;
25420a96aa3bSJed Brown       sc_array_t        coarseQuadsArray;
25430a96aa3bSJed Brown 
25440a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
2545792fecdfSBarry Smith       PetscCallP4est(sc_array_init_data, (&coarseQuadsArray, coarseQuads, sizeof(p4est_quadrant_t), (size_t)numCoarseQuads));
25460a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
25470a96aa3bSJed Brown         PetscInt          c          = i + offset;
25480a96aa3bSJed Brown         p4est_quadrant_t *quad       = &fineQuads[i];
25490a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
25500a96aa3bSJed Brown         ssize_t           disjoint   = -1;
25510a96aa3bSJed Brown 
25520a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
25530a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
2554792fecdfSBarry Smith           PetscCallP4estReturn(disjoint, p4est_quadrant_disjoint, (quadCoarse, quad));
25550a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
25560a96aa3bSJed Brown         }
255708401ef6SPierre Jolivet         PetscCheck(disjoint == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "did not find overlapping coarse quad");
25580a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
25590a96aa3bSJed Brown           if (transferIdent) {                                                                         /* find corners */
25600a96aa3bSJed Brown             PetscInt j = 0;
25610a96aa3bSJed Brown 
25620a96aa3bSJed Brown             do {
25630a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
25640a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
25650a96aa3bSJed Brown                 int              equal;
25660a96aa3bSJed Brown 
2567792fecdfSBarry Smith                 PetscCallP4est(p4est_quadrant_corner_descendant, (quad, &cornerQuad, j, quadCoarse->level));
2568792fecdfSBarry Smith                 PetscCallP4estReturn(equal, p4est_quadrant_is_equal, (&cornerQuad, quadCoarse));
25690a96aa3bSJed Brown                 if (equal) {
25700a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
25710a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
25720a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
25730a96aa3bSJed Brown 
25740a96aa3bSJed Brown                   roots[p - pStartF]    = q;
25750a96aa3bSJed Brown                   rootType[p - pStartF] = PETSC_MAX_INT;
25760a96aa3bSJed Brown                   cids[p - pStartF]     = -1;
25770a96aa3bSJed Brown                   j++;
25780a96aa3bSJed Brown                 }
25790a96aa3bSJed Brown               }
25800a96aa3bSJed Brown               coarseCount++;
25810a96aa3bSJed Brown               disjoint = 1;
25820a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
25830a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
2584792fecdfSBarry Smith                 PetscCallP4estReturn(disjoint, p4est_quadrant_disjoint, (quadCoarse, quad));
25850a96aa3bSJed Brown               }
25860a96aa3bSJed Brown             } while (!disjoint);
25870a96aa3bSJed Brown           }
25880a96aa3bSJed Brown           continue;
25890a96aa3bSJed Brown         }
25900a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
25910a96aa3bSJed Brown           PetscInt j;
25920a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
25930a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
25940a96aa3bSJed Brown 
25950a96aa3bSJed Brown             roots[p - pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
25960a96aa3bSJed Brown             rootType[p - pStartF] = PETSC_MAX_INT; /* unconditionally accept */
25970a96aa3bSJed Brown             cids[p - pStartF]     = -1;
25980a96aa3bSJed Brown           }
25990a96aa3bSJed Brown         } else {
26000a96aa3bSJed Brown           PetscInt levelDiff                 = quad->level - quadCoarse->level;
26010a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
26020a96aa3bSJed Brown 
26030a96aa3bSJed Brown           if (formCids) {
26040a96aa3bSJed Brown             PetscInt  cl;
26050a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
26060a96aa3bSJed Brown             int       cid;
26070a96aa3bSJed Brown 
260808401ef6SPierre Jolivet             PetscCheck(levelDiff <= 1, PETSC_COMM_SELF, PETSC_ERR_USER, "Recursive child ids not implemented");
2609792fecdfSBarry Smith             PetscCallP4estReturn(cid, p4est_quadrant_child_id, (quad));
26109566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(plexF, c + cLocalStartF, PETSC_TRUE, NULL, &pointClosure));
26110a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
26120a96aa3bSJed Brown               PetscInt       p      = pointClosure[2 * cl];
26130a96aa3bSJed Brown               PetscInt       point  = childClosures[cid][2 * cl];
26140a96aa3bSJed Brown               PetscInt       ornt   = childClosures[cid][2 * cl + 1];
26150a96aa3bSJed Brown               PetscInt       newcid = -1;
26160a96aa3bSJed Brown               DMPolytopeType ct;
26170a96aa3bSJed Brown 
26180a96aa3bSJed Brown               if (rootType[p - pStartF] == PETSC_MAX_INT) continue;
26199566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCellType(refTree, point, &ct));
26200a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
26210a96aa3bSJed Brown               if (!cl) {
26220a96aa3bSJed Brown                 newcid = cid + 1;
26230a96aa3bSJed Brown               } else {
26240a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
26250a96aa3bSJed Brown 
26269566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetTreeParent(refTree, point, &parent, NULL));
26270a96aa3bSJed Brown                 if (parent == point) {
26280a96aa3bSJed Brown                   newcid = -1;
26290a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
26300a96aa3bSJed Brown                   newcid = point;
26310a96aa3bSJed Brown                 } else {
26320a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
26330a96aa3bSJed Brown 
26340a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
26350a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
26369566063dSJacob Faibussowitsch                       PetscCall(DMPlexGetCellType(refTree, parent, &rct));
26370a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
26380a96aa3bSJed Brown                       break;
26390a96aa3bSJed Brown                     }
26400a96aa3bSJed Brown                   }
264108401ef6SPierre Jolivet                   PetscCheck(rcl < P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Couldn't find parent in root closure");
26429566063dSJacob Faibussowitsch                   PetscCall(DMPlexReferenceTreeGetChildSymmetry(refTree, parent, parentOrnt, ornt, point, DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]), NULL, &newcid));
26430a96aa3bSJed Brown                 }
26440a96aa3bSJed Brown               }
26450a96aa3bSJed Brown               if (newcid >= 0) {
264648a46eb9SPierre Jolivet                 if (canonical) PetscCall(DMLabelGetValue(canonical, newcid, &newcid));
26470a96aa3bSJed Brown                 proposedCids[cl] = newcid;
26480a96aa3bSJed Brown               }
26490a96aa3bSJed Brown             }
26509566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(plexF, c + cLocalStartF, PETSC_TRUE, NULL, &pointClosure));
26510a96aa3bSJed Brown           }
26529371c9d4SSatish Balay           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {
26539371c9d4SSatish Balay             {quadCoarse->x, quadCoarse->y,
26540a96aa3bSJed Brown   #if defined(P4_TO_P8)
26550a96aa3bSJed Brown              quadCoarse->z
26560a96aa3bSJed Brown   #endif
26579371c9d4SSatish Balay             },
26589371c9d4SSatish Balay             {0}
26599371c9d4SSatish Balay           };
26609371c9d4SSatish Balay           p4est_qcoord_t fineBound[2][P4EST_DIM] = {
26619371c9d4SSatish Balay             {quad->x, quad->y,
26620a96aa3bSJed Brown   #if defined(P4_TO_P8)
26630a96aa3bSJed Brown              quad->z
26640a96aa3bSJed Brown   #endif
26659371c9d4SSatish Balay             },
26669371c9d4SSatish Balay             {0}
26679371c9d4SSatish Balay           };
26680a96aa3bSJed Brown           PetscInt j;
26690a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
26700a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
26710a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j] + P4EST_QUADRANT_LEN(quad->level);
26720a96aa3bSJed Brown           }
26730a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
26740a96aa3bSJed Brown             PetscInt    l, p;
26750a96aa3bSJed Brown             PetscSFNode q;
26760a96aa3bSJed Brown 
26770a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
26780a96aa3bSJed Brown             if (rootType[p - pStartF] == PETSC_MAX_INT) continue;
26790a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
26800a96aa3bSJed Brown               l = 0;
26810a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
26820a96aa3bSJed Brown               PetscInt face       = PetscFaceToP4estFace[j - 1];
26830a96aa3bSJed Brown               PetscInt direction  = face / 2;
26840a96aa3bSJed Brown               PetscInt coarseFace = -1;
26850a96aa3bSJed Brown 
26860a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
26870a96aa3bSJed Brown                 coarseFace = face;
26880a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
26890a96aa3bSJed Brown               } else {
26900a96aa3bSJed Brown                 l = 0;
26910a96aa3bSJed Brown               }
26920a96aa3bSJed Brown   #if defined(P4_TO_P8)
26930a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
26940a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
26950a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
26960a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
26970a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
26980a96aa3bSJed Brown               PetscInt  minDir = PetscMin((direction + 1) % 3, (direction + 2) % 3);
26990a96aa3bSJed Brown               PetscInt  maxDir = PetscMax((direction + 1) % 3, (direction + 2) % 3);
27000a96aa3bSJed Brown               PetscBool dirTest[2];
27010a96aa3bSJed Brown 
27020a96aa3bSJed Brown               dirTest[0] = (PetscBool)(coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
27030a96aa3bSJed Brown               dirTest[1] = (PetscBool)(coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
27040a96aa3bSJed Brown 
27050a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
27060a96aa3bSJed Brown                 coarseEdge = edge;
27070a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27080a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
27090a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
27100a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
27110a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
27120a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
27130a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
27140a96aa3bSJed Brown               } else {
27150a96aa3bSJed Brown                 l = 0;
27160a96aa3bSJed Brown               }
27170a96aa3bSJed Brown   #endif
27180a96aa3bSJed Brown             } else {
27190a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
27200a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
27210a96aa3bSJed Brown               PetscInt  m;
27220a96aa3bSJed Brown               PetscInt  numMatch     = 0;
27230a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
27240a96aa3bSJed Brown   #if defined(P4_TO_P8)
27250a96aa3bSJed Brown               PetscInt coarseEdge = -1;
27260a96aa3bSJed Brown   #endif
27270a96aa3bSJed Brown 
27280a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
27290a96aa3bSJed Brown                 dirTest[m] = (PetscBool)(coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
27300a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
27310a96aa3bSJed Brown               }
27320a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
27330a96aa3bSJed Brown                 coarseVertex = vertex;
27340a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
27350a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
27360a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27370a96aa3bSJed Brown                   if (dirTest[m]) {
27380a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
27390a96aa3bSJed Brown                     break;
27400a96aa3bSJed Brown                   }
27410a96aa3bSJed Brown                 }
27420a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27430a96aa3bSJed Brown   #if defined(P4_TO_P8)
27440a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
27450a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27460a96aa3bSJed Brown                   if (!dirTest[m]) {
27470a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
27480a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
27490a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1, otherDir2);
27500a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1, otherDir2);
27510a96aa3bSJed Brown 
27520a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
27530a96aa3bSJed Brown                     break;
27540a96aa3bSJed Brown                   }
27550a96aa3bSJed Brown                 }
27560a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27570a96aa3bSJed Brown   #endif
27580a96aa3bSJed Brown               } else { /* volume */
27590a96aa3bSJed Brown                 l = 0;
27600a96aa3bSJed Brown               }
27610a96aa3bSJed Brown             }
27620a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
27630a96aa3bSJed Brown             if (l > rootType[p - pStartF]) {
27640a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
27650a96aa3bSJed Brown                 if (transferIdent) {
27660a96aa3bSJed Brown                   roots[p - pStartF]    = q;
27670a96aa3bSJed Brown                   rootType[p - pStartF] = PETSC_MAX_INT;
27680a96aa3bSJed Brown                   if (formCids) cids[p - pStartF] = -1;
27690a96aa3bSJed Brown                 }
27700a96aa3bSJed Brown               } else {
27710a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
27720a96aa3bSJed Brown 
27730a96aa3bSJed Brown                 roots[p - pStartF]    = q;
27740a96aa3bSJed Brown                 rootType[p - pStartF] = l;
27750a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
27760a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
27770a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
27780a96aa3bSJed Brown                   PetscInt parent;
27790a96aa3bSJed Brown 
27809566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetTreeParent(plexF, thisp, &parent, NULL));
27810a96aa3bSJed Brown                   if (parent == thisp) break;
27820a96aa3bSJed Brown 
27830a96aa3bSJed Brown                   roots[parent - pStartF]    = q;
27840a96aa3bSJed Brown                   rootType[parent - pStartF] = PETSC_MAX_INT;
27850a96aa3bSJed Brown                   if (formCids) cids[parent - pStartF] = -1;
27860a96aa3bSJed Brown                   thisp = parent;
27870a96aa3bSJed Brown                 }
27880a96aa3bSJed Brown               }
27890a96aa3bSJed Brown             }
27900a96aa3bSJed Brown           }
27910a96aa3bSJed Brown         }
27920a96aa3bSJed Brown       }
27930a96aa3bSJed Brown     }
27940a96aa3bSJed Brown 
27950a96aa3bSJed 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 */
27960a96aa3bSJed Brown     if (size > 1) {
27970a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
27980a96aa3bSJed Brown 
27999566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &rootTypeCopy));
28009566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(rootTypeCopy, rootType, pEndF - pStartF));
280157168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_MAX));
280257168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_MAX));
28039566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_REPLACE));
28049566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_REPLACE));
28050a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28060a96aa3bSJed 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 */
28070a96aa3bSJed Brown           roots[p - pStartF].rank  = -1;
28080a96aa3bSJed Brown           roots[p - pStartF].index = -1;
28090a96aa3bSJed Brown         }
28109371c9d4SSatish 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 */ }
28110a96aa3bSJed Brown       }
28129566063dSJacob Faibussowitsch       PetscCall(PetscFree(rootTypeCopy));
28139566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF, nodeType, roots, roots, sfNodeReduce));
28149566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF, nodeType, roots, roots, sfNodeReduce));
28159566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, nodeType, roots, roots, MPI_REPLACE));
28169566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, nodeType, roots, roots, MPI_REPLACE));
28170a96aa3bSJed Brown     }
28189566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootType));
28190a96aa3bSJed Brown 
28200a96aa3bSJed Brown     {
28210a96aa3bSJed Brown       PetscInt     numRoots;
28220a96aa3bSJed Brown       PetscInt     numLeaves;
28230a96aa3bSJed Brown       PetscInt    *leaves;
28240a96aa3bSJed Brown       PetscSFNode *iremote;
28250a96aa3bSJed Brown       /* count leaves */
28260a96aa3bSJed Brown 
28270a96aa3bSJed Brown       numRoots = pEndC - pStartC;
28280a96aa3bSJed Brown 
28290a96aa3bSJed Brown       numLeaves = 0;
28300a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28310a96aa3bSJed Brown         if (roots[p - pStartF].index >= 0) numLeaves++;
28320a96aa3bSJed Brown       }
28339566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves, &leaves));
28349566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves, &iremote));
28350a96aa3bSJed Brown       numLeaves = 0;
28360a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28370a96aa3bSJed Brown         if (roots[p - pStartF].index >= 0) {
28380a96aa3bSJed Brown           leaves[numLeaves]  = p - pStartF;
28390a96aa3bSJed Brown           iremote[numLeaves] = roots[p - pStartF];
28400a96aa3bSJed Brown           numLeaves++;
28410a96aa3bSJed Brown         }
28420a96aa3bSJed Brown       }
28439566063dSJacob Faibussowitsch       PetscCall(PetscFree(roots));
28449566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, sf));
28450a96aa3bSJed Brown       if (numLeaves == (pEndF - pStartF)) {
28469566063dSJacob Faibussowitsch         PetscCall(PetscFree(leaves));
28479566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf, numRoots, numLeaves, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
28480a96aa3bSJed Brown       } else {
28499566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf, numRoots, numLeaves, leaves, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
28500a96aa3bSJed Brown       }
28510a96aa3bSJed Brown     }
28520a96aa3bSJed Brown     if (formCids) {
28530a96aa3bSJed Brown       PetscSF  pointSF;
28540a96aa3bSJed Brown       PetscInt child;
28550a96aa3bSJed Brown 
28569566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF, &refTree));
28579566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(plexF, &pointSF));
285857168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, cids, cids, MPI_MAX));
285957168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, cids, cids, MPI_MAX));
28600a96aa3bSJed Brown       if (childIds) *childIds = cids;
286148a46eb9SPierre Jolivet       for (child = 0; child < P4EST_CHILDREN; child++) PetscCall(DMPlexRestoreTransitiveClosure(refTree, child + 1, PETSC_TRUE, NULL, &childClosures[child]));
28629566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(refTree, 0, PETSC_TRUE, NULL, &rootClosure));
28630a96aa3bSJed Brown     }
28640a96aa3bSJed Brown   }
28650a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
28669566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
28670a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
28680a96aa3bSJed Brown     if (!childIds) {
28690a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
28700a96aa3bSJed Brown     } else {
28719566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &pforestC->pointSelfToAdaptCids));
28729566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestC->pointSelfToAdaptCids, cids, pEndF - pStartF));
28730a96aa3bSJed Brown     }
28740a96aa3bSJed Brown   } else if (saveInFine) {
28759566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
28760a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
28770a96aa3bSJed Brown     if (!childIds) {
28780a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
28790a96aa3bSJed Brown     } else {
28809566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &pforestF->pointAdaptToSelfCids));
28819566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestF->pointAdaptToSelfCids, cids, pEndF - pStartF));
28820a96aa3bSJed Brown     }
28830a96aa3bSJed Brown   }
28849566063dSJacob Faibussowitsch   PetscCall(PetscFree2(treeQuads, treeQuadCounts));
28859566063dSJacob Faibussowitsch   PetscCall(PetscFree(coverQuads));
28869566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsC));
28879566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsF));
28889566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeClosureType));
28899566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_free(&sfNodeReduce));
28909566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
28913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28920a96aa3bSJed Brown }
28930a96aa3bSJed Brown 
28940a96aa3bSJed Brown /* children are sf leaves of parents */
2895d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
2896d71ae5a4SJacob Faibussowitsch {
28970a96aa3bSJed Brown   MPI_Comm           comm;
2898d70f29a3SPierre Jolivet   PetscMPIInt        rank;
28990a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
29000a96aa3bSJed Brown   DM                 plexC, plexF;
29010a96aa3bSJed Brown   PetscInt           pStartC, pEndC, pStartF, pEndF;
29020a96aa3bSJed Brown   PetscSF            pointTransferSF;
29030a96aa3bSJed Brown   PetscBool          allOnes = PETSC_TRUE;
29040a96aa3bSJed Brown 
29050a96aa3bSJed Brown   PetscFunctionBegin;
29060a96aa3bSJed Brown   pforestC = (DM_Forest_pforest *)((DM_Forest *)coarse->data)->data;
29070a96aa3bSJed Brown   pforestF = (DM_Forest_pforest *)((DM_Forest *)fine->data)->data;
290808401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo, PetscObjectComm((PetscObject)coarse), PETSC_ERR_ARG_INCOMP, "DM's must have the same base DM");
29090a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
29109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
29110a96aa3bSJed Brown 
29120a96aa3bSJed Brown   {
29130a96aa3bSJed Brown     PetscInt i;
29140a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
29150a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
29160a96aa3bSJed Brown         allOnes = PETSC_FALSE;
29170a96aa3bSJed Brown         break;
29180a96aa3bSJed Brown       }
29190a96aa3bSJed Brown     }
29200a96aa3bSJed Brown   }
29219566063dSJacob Faibussowitsch   PetscCall(DMPforestGetTransferSF_Point(coarse, fine, &pointTransferSF, transferIdent, childIds));
29220a96aa3bSJed Brown   if (allOnes) {
29230a96aa3bSJed Brown     *sf = pointTransferSF;
29243ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
29250a96aa3bSJed Brown   }
29260a96aa3bSJed Brown 
29279566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine, &plexF));
29289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF, &pStartF, &pEndF));
29299566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse, &plexC));
29309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC, &pStartC, &pEndC));
29310a96aa3bSJed Brown   {
29320a96aa3bSJed Brown     PetscInt           numRoots;
29330a96aa3bSJed Brown     PetscInt           numLeaves;
29340a96aa3bSJed Brown     const PetscInt    *leaves;
29350a96aa3bSJed Brown     const PetscSFNode *iremote;
29360a96aa3bSJed Brown     PetscInt           d;
29370a96aa3bSJed Brown     PetscSection       leafSection, rootSection;
29380a96aa3bSJed Brown     /* count leaves */
29390a96aa3bSJed Brown 
29409566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointTransferSF, &numRoots, &numLeaves, &leaves, &iremote));
29419566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &rootSection));
29429566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &leafSection));
29439566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(rootSection, pStartC, pEndC));
29449566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(leafSection, pStartF, pEndF));
29450a96aa3bSJed Brown 
29460a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
29470a96aa3bSJed Brown       PetscInt startC, endC, e;
29480a96aa3bSJed Brown 
29499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC, P4EST_DIM - d, &startC, &endC));
295048a46eb9SPierre Jolivet       for (e = startC; e < endC; e++) PetscCall(PetscSectionSetDof(rootSection, e, dofPerDim[d]));
29510a96aa3bSJed Brown     }
29520a96aa3bSJed Brown 
29530a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
29540a96aa3bSJed Brown       PetscInt startF, endF, e;
29550a96aa3bSJed Brown 
29569566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexF, P4EST_DIM - d, &startF, &endF));
295748a46eb9SPierre Jolivet       for (e = startF; e < endF; e++) PetscCall(PetscSectionSetDof(leafSection, e, dofPerDim[d]));
29580a96aa3bSJed Brown     }
29590a96aa3bSJed Brown 
29609566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(rootSection));
29619566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafSection));
29620a96aa3bSJed Brown     {
29630a96aa3bSJed Brown       PetscInt     nroots, nleaves;
29640a96aa3bSJed Brown       PetscInt    *mine, i, p;
29650a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
29660a96aa3bSJed Brown       PetscSFNode *remote;
29670a96aa3bSJed Brown 
29689566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &offsets));
29699566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndC - pStartC, &offsetsRoot));
297048a46eb9SPierre Jolivet       for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionGetOffset(rootSection, p, &offsetsRoot[p - pStartC]));
29719566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointTransferSF, MPIU_INT, offsetsRoot, offsets, MPI_REPLACE));
29729566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointTransferSF, MPIU_INT, offsetsRoot, offsets, MPI_REPLACE));
29739566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(rootSection, &nroots));
29740a96aa3bSJed Brown       nleaves = 0;
29750a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
29760a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
29770a96aa3bSJed Brown         PetscInt dof;
29780a96aa3bSJed Brown 
29799566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection, leaf, &dof));
29800a96aa3bSJed Brown         nleaves += dof;
29810a96aa3bSJed Brown       }
29829566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &mine));
29839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &remote));
29840a96aa3bSJed Brown       nleaves = 0;
29850a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
29860a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
29870a96aa3bSJed Brown         PetscInt dof;
29880a96aa3bSJed Brown         PetscInt off, j;
29890a96aa3bSJed Brown 
29909566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection, leaf, &dof));
29919566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafSection, leaf, &off));
29920a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
29930a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
29940a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
29950a96aa3bSJed Brown           mine[nleaves++]       = off + j;
29960a96aa3bSJed Brown         }
29970a96aa3bSJed Brown       }
29989566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsetsRoot));
29999566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsets));
30009566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, sf));
30019566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
30020a96aa3bSJed Brown     }
30039566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
30049566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootSection));
30059566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointTransferSF));
30060a96aa3bSJed Brown   }
30073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30080a96aa3bSJed Brown }
30090a96aa3bSJed Brown 
3010d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA)
3011d71ae5a4SJacob Faibussowitsch {
30120a96aa3bSJed Brown   DM          adaptA, adaptB;
30130a96aa3bSJed Brown   DMAdaptFlag purpose;
30140a96aa3bSJed Brown 
30150a96aa3bSJed Brown   PetscFunctionBegin;
30169566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmA, &adaptA));
30179566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmB, &adaptB));
30180a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
30190a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
30209566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmA, &purpose));
30210a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
30229566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30233ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
30240a96aa3bSJed Brown     }
30250a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
30269566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmB, &purpose));
30270a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
30289566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30293ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
30300a96aa3bSJed Brown     }
30310a96aa3bSJed Brown   }
30321baa6e33SBarry Smith   if (sfAtoB) PetscCall(DMPforestGetTransferSF_Internal(dmA, dmB, dofPerDim, sfAtoB, PETSC_TRUE, NULL));
30331baa6e33SBarry Smith   if (sfBtoA) PetscCall(DMPforestGetTransferSF_Internal(dmB, dmA, dofPerDim, sfBtoA, (PetscBool)(sfAtoB == NULL), NULL));
30343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30350a96aa3bSJed Brown }
30360a96aa3bSJed Brown 
3037d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex)
3038d71ae5a4SJacob Faibussowitsch {
30390a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
30400a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
30410a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
30420a96aa3bSJed Brown   PetscInt           cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
30430a96aa3bSJed Brown   PetscInt           pStart, pEnd, pStartBase, pEndBase, p;
30440a96aa3bSJed Brown   DM                 base;
30450a96aa3bSJed Brown   PetscInt          *star      = NULL, starSize;
30460a96aa3bSJed Brown   DMLabelLink        next      = dm->labels;
30470a96aa3bSJed Brown   PetscInt           guess     = 0;
30480a96aa3bSJed Brown   p4est_topidx_t     num_trees = pforest->topo->conn->num_trees;
30490a96aa3bSJed Brown 
30500a96aa3bSJed Brown   PetscFunctionBegin;
30510a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
30520a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
30530a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
30549566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
30550a96aa3bSJed Brown   if (!base) {
30560a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
30570a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
30580a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
30590a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t *)p4est->trees->array;
30600a96aa3bSJed Brown       p4est_topidx_t        t, flt = p4est->first_local_tree;
30610a96aa3bSJed Brown       p4est_topidx_t        llt = pforest->forest->last_local_tree;
30620a96aa3bSJed Brown       DMLabel               ghostLabel;
30630a96aa3bSJed Brown       PetscInt              c;
30640a96aa3bSJed Brown 
30659566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(plex, pforest->ghostName));
30669566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(plex, pforest->ghostName, &ghostLabel));
30670a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
30680a96aa3bSJed Brown         p4est_tree_t     *tree     = &trees[t];
30690a96aa3bSJed Brown         p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
30700a96aa3bSJed Brown         PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
30710a96aa3bSJed Brown         PetscInt          q;
30720a96aa3bSJed Brown 
30730a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
30740a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
30750a96aa3bSJed Brown           PetscInt          f;
30760a96aa3bSJed Brown 
30770a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
30780a96aa3bSJed Brown             p4est_quadrant_t neigh;
30790a96aa3bSJed Brown             int              isOutside;
30800a96aa3bSJed Brown 
3081792fecdfSBarry Smith             PetscCallP4est(p4est_quadrant_face_neighbor, (quad, f, &neigh));
3082792fecdfSBarry Smith             PetscCallP4estReturn(isOutside, p4est_quadrant_is_outside_face, (&neigh));
30830a96aa3bSJed Brown             if (isOutside) {
30840a96aa3bSJed Brown               p4est_topidx_t nt;
30850a96aa3bSJed Brown               PetscInt       nf;
30860a96aa3bSJed Brown 
30870a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
30880a96aa3bSJed Brown               nf = (PetscInt)conn->tree_to_face[t * P4EST_FACES + f];
30890a96aa3bSJed Brown               nf = nf % P4EST_FACES;
30900a96aa3bSJed Brown               if (nt == t && nf == f) {
30910a96aa3bSJed Brown                 PetscInt        plexF = P4estFaceToPetscFace[f];
30920a96aa3bSJed Brown                 const PetscInt *cone;
30930a96aa3bSJed Brown 
30949566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetCone(plex, c, &cone));
30959566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(ghostLabel, cone[plexF], plexF + 1));
30960a96aa3bSJed Brown               }
30970a96aa3bSJed Brown             }
30980a96aa3bSJed Brown           }
30990a96aa3bSJed Brown         }
31000a96aa3bSJed Brown       }
31010a96aa3bSJed Brown     }
31023ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
31030a96aa3bSJed Brown   }
31049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, 0, &cStartBase, &cEndBase));
31059566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, 1, &fStartBase, &fEndBase));
31069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, P4EST_DIM - 1, &eStartBase, &eEndBase));
31079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(base, 0, &vStartBase, &vEndBase));
31080a96aa3bSJed Brown 
31099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd));
31109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 1, &fStart, &fEnd));
31119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, P4EST_DIM - 1, &eStart, &eEnd));
31129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
31130a96aa3bSJed Brown 
31149566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &pStart, &pEnd));
31159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(base, &pStartBase, &pEndBase));
31160a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
31170a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
31180a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
31190a96aa3bSJed Brown   while (next) {
31200a96aa3bSJed Brown     DMLabel     baseLabel;
31210a96aa3bSJed Brown     DMLabel     label = next->label;
31220a96aa3bSJed Brown     PetscBool   isDepth, isCellType, isGhost, isVTK, isSpmap;
31230a96aa3bSJed Brown     const char *name;
31240a96aa3bSJed Brown 
31259566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)label, &name));
31269566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "depth", &isDepth));
31270a96aa3bSJed Brown     if (isDepth) {
31280a96aa3bSJed Brown       next = next->next;
31290a96aa3bSJed Brown       continue;
31300a96aa3bSJed Brown     }
31319566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "celltype", &isCellType));
31320a96aa3bSJed Brown     if (isCellType) {
31330a96aa3bSJed Brown       next = next->next;
31340a96aa3bSJed Brown       continue;
31350a96aa3bSJed Brown     }
31369566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "ghost", &isGhost));
31370a96aa3bSJed Brown     if (isGhost) {
31380a96aa3bSJed Brown       next = next->next;
31390a96aa3bSJed Brown       continue;
31400a96aa3bSJed Brown     }
31419566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "vtk", &isVTK));
31420a96aa3bSJed Brown     if (isVTK) {
31430a96aa3bSJed Brown       next = next->next;
31440a96aa3bSJed Brown       continue;
31450a96aa3bSJed Brown     }
31469566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "_forest_base_subpoint_map", &isSpmap));
31470a96aa3bSJed Brown     if (!isSpmap) {
31489566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(base, name, &baseLabel));
31490a96aa3bSJed Brown       if (!baseLabel) {
31500a96aa3bSJed Brown         next = next->next;
31510a96aa3bSJed Brown         continue;
31520a96aa3bSJed Brown       }
31539566063dSJacob Faibussowitsch       PetscCall(DMLabelCreateIndex(baseLabel, pStartBase, pEndBase));
31540a96aa3bSJed Brown     } else baseLabel = NULL;
31550a96aa3bSJed Brown 
31560a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
31570a96aa3bSJed Brown       PetscInt          s, c = -1, l;
31580a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
31590a96aa3bSJed Brown       p4est_quadrant_t *ghosts  = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
31600a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t *)pforest->forest->trees->array;
31610a96aa3bSJed Brown       p4est_quadrant_t *q;
31620a96aa3bSJed Brown       PetscInt          t, val;
31630a96aa3bSJed Brown       PetscBool         zerosupportpoint = PETSC_FALSE;
31640a96aa3bSJed Brown 
31659566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
31660a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
31670a96aa3bSJed Brown         PetscInt point = star[2 * s];
31680a96aa3bSJed Brown 
31690a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
31709566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(plex, point, PETSC_TRUE, &closureSize, &closure));
31710a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
31720a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
31730a96aa3bSJed Brown             do { /* check parents of q */
31740a96aa3bSJed Brown               q = qParent;
31750a96aa3bSJed Brown               if (q == p) {
31760a96aa3bSJed Brown                 c = point;
31770a96aa3bSJed Brown                 break;
31780a96aa3bSJed Brown               }
31799566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex, q, &qParent, NULL));
31800a96aa3bSJed Brown             } while (qParent != q);
31810a96aa3bSJed Brown             if (c != -1) break;
31829566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(plex, pp, &pParent, NULL));
31830a96aa3bSJed Brown             q = closure[2 * l];
31840a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
31850a96aa3bSJed Brown               pp = pParent;
31860a96aa3bSJed Brown               if (pp == q) {
31870a96aa3bSJed Brown                 c = point;
31880a96aa3bSJed Brown                 break;
31890a96aa3bSJed Brown               }
31909566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex, pp, &pParent, NULL));
31910a96aa3bSJed Brown             }
31920a96aa3bSJed Brown             if (c != -1) break;
31930a96aa3bSJed Brown           }
31949566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(plex, point, PETSC_TRUE, NULL, &closure));
31950a96aa3bSJed Brown           if (l < closureSize) break;
31960a96aa3bSJed Brown         } else {
31970a96aa3bSJed Brown           PetscInt supportSize;
31980a96aa3bSJed Brown 
31999566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(plex, point, &supportSize));
32000a96aa3bSJed Brown           zerosupportpoint = (PetscBool)(zerosupportpoint || !supportSize);
32010a96aa3bSJed Brown         }
32020a96aa3bSJed Brown       }
32030a96aa3bSJed Brown       if (c < 0) {
32040a96aa3bSJed Brown         const char *prefix;
32050a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
32060a96aa3bSJed Brown 
32079566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
32089566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, prefix, "-dm_forest_print_label_error", &print, NULL));
32090a96aa3bSJed Brown         if (print) {
32100a96aa3bSJed Brown           PetscInt i;
32110a96aa3bSJed Brown 
321263a3b9bcSJacob 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));
321363a3b9bcSJacob 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]));
32140a96aa3bSJed Brown         }
32159566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, NULL, &star));
32160a96aa3bSJed Brown         if (zerosupportpoint) continue;
32179371c9d4SSatish Balay         else
32189371c9d4SSatish 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");
32190a96aa3bSJed Brown       }
32209566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, NULL, &star));
32210a96aa3bSJed Brown 
32220a96aa3bSJed Brown       if (c < cLocalStart) {
32230a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
32240a96aa3bSJed Brown         q = &(ghosts[c]);
32250a96aa3bSJed Brown         t = (PetscInt)q->p.which_tree;
32260a96aa3bSJed Brown       } else if (c < cLocalEnd) {
32270a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
32280a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
32290a96aa3bSJed Brown 
32300a96aa3bSJed Brown         c -= cLocalStart;
32310a96aa3bSJed Brown 
32320a96aa3bSJed Brown         do {
32330a96aa3bSJed Brown           p4est_tree_t *tree;
32340a96aa3bSJed Brown 
32351dca8a05SBarry Smith           PetscCheck(guess >= lo && guess < num_trees && lo < hi, PETSC_COMM_SELF, PETSC_ERR_PLIB, "failed binary search");
32360a96aa3bSJed Brown           tree = &trees[guess];
32370a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
32380a96aa3bSJed Brown             hi = guess;
32390a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt)tree->quadrants.elem_count) {
32400a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt)tree->quadrants_offset];
32410a96aa3bSJed Brown             t = guess;
32420a96aa3bSJed Brown             break;
32430a96aa3bSJed Brown           } else {
32440a96aa3bSJed Brown             lo = guess + 1;
32450a96aa3bSJed Brown           }
32460a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
32470a96aa3bSJed Brown         } while (1);
32480a96aa3bSJed Brown       } else {
32490a96aa3bSJed Brown         /* get from the end of the ghost layer */
32500a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
32510a96aa3bSJed Brown 
32520a96aa3bSJed Brown         q = &(ghosts[c]);
32530a96aa3bSJed Brown         t = (PetscInt)q->p.which_tree;
32540a96aa3bSJed Brown       }
32550a96aa3bSJed Brown 
32560a96aa3bSJed Brown       if (l == 0) { /* cell */
32570a96aa3bSJed Brown         if (baseLabel) {
32589566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32590a96aa3bSJed Brown         } else {
32600a96aa3bSJed Brown           val = t + cStartBase;
32610a96aa3bSJed Brown         }
32629566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label, p, val));
32630a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
32640a96aa3bSJed Brown         p4est_quadrant_t nq;
32650a96aa3bSJed Brown         int              isInside;
32660a96aa3bSJed Brown 
32670a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
3268792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_face_neighbor, (q, l, &nq));
3269792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
32700a96aa3bSJed Brown         if (isInside) {
32710a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
32720a96aa3bSJed Brown           if (baseLabel) {
32739566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32740a96aa3bSJed Brown           } else {
32750a96aa3bSJed Brown             val = t + cStartBase;
32760a96aa3bSJed Brown           }
32779566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32780a96aa3bSJed Brown         } else {
32790a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
32800a96aa3bSJed Brown 
32810a96aa3bSJed Brown           if (baseLabel) {
32829566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
32830a96aa3bSJed Brown           } else {
32840a96aa3bSJed Brown             val = f + fStartBase;
32850a96aa3bSJed Brown           }
32869566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32870a96aa3bSJed Brown         }
32880a96aa3bSJed Brown   #if defined(P4_TO_P8)
32890a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
32900a96aa3bSJed Brown         p4est_quadrant_t nq;
32910a96aa3bSJed Brown         int              isInside;
32920a96aa3bSJed Brown 
32930a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
3294792fecdfSBarry Smith         PetscCallP4est(p8est_quadrant_edge_neighbor, (q, l, &nq));
3295792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
32960a96aa3bSJed Brown         if (isInside) {
32970a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
32980a96aa3bSJed Brown           if (baseLabel) {
32999566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
33000a96aa3bSJed Brown           } else {
33010a96aa3bSJed Brown             val = t + cStartBase;
33020a96aa3bSJed Brown           }
33039566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
33040a96aa3bSJed Brown         } else {
33050a96aa3bSJed Brown           int isOutsideFace;
33060a96aa3bSJed Brown 
3307792fecdfSBarry Smith           PetscCallP4estReturn(isOutsideFace, p4est_quadrant_is_outside_face, (&nq));
33080a96aa3bSJed Brown           if (isOutsideFace) {
33090a96aa3bSJed Brown             PetscInt f;
33100a96aa3bSJed Brown 
33110a96aa3bSJed Brown             if (nq.x < 0) {
33120a96aa3bSJed Brown               f = 0;
33130a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33140a96aa3bSJed Brown               f = 1;
33150a96aa3bSJed Brown             } else if (nq.y < 0) {
33160a96aa3bSJed Brown               f = 2;
33170a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33180a96aa3bSJed Brown               f = 3;
33190a96aa3bSJed Brown             } else if (nq.z < 0) {
33200a96aa3bSJed Brown               f = 4;
33210a96aa3bSJed Brown             } else {
33220a96aa3bSJed Brown               f = 5;
33230a96aa3bSJed Brown             }
33240a96aa3bSJed Brown             f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33250a96aa3bSJed Brown             if (baseLabel) {
33269566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
33270a96aa3bSJed Brown             } else {
33280a96aa3bSJed Brown               val = f + fStartBase;
33290a96aa3bSJed Brown             }
33309566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33310a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
33320a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
33330a96aa3bSJed Brown 
33340a96aa3bSJed Brown             if (baseLabel) {
33359566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, e + eStartBase, &val));
33360a96aa3bSJed Brown             } else {
33370a96aa3bSJed Brown               val = e + eStartBase;
33380a96aa3bSJed Brown             }
33399566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33400a96aa3bSJed Brown           }
33410a96aa3bSJed Brown         }
33420a96aa3bSJed Brown   #endif
33430a96aa3bSJed Brown       } else { /* vertex */
33440a96aa3bSJed Brown         p4est_quadrant_t nq;
33450a96aa3bSJed Brown         int              isInside;
33460a96aa3bSJed Brown 
33470a96aa3bSJed Brown   #if defined(P4_TO_P8)
33480a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
33490a96aa3bSJed Brown   #else
33500a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
33510a96aa3bSJed Brown   #endif
3352792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_corner_neighbor, (q, l, &nq));
3353792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
33540a96aa3bSJed Brown         if (isInside) {
33550a96aa3bSJed Brown           if (baseLabel) {
33569566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
33570a96aa3bSJed Brown           } else {
33580a96aa3bSJed Brown             val = t + cStartBase;
33590a96aa3bSJed Brown           }
33609566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
33610a96aa3bSJed Brown         } else {
33620a96aa3bSJed Brown           int isOutside;
33630a96aa3bSJed Brown 
3364792fecdfSBarry Smith           PetscCallP4estReturn(isOutside, p4est_quadrant_is_outside_face, (&nq));
33650a96aa3bSJed Brown           if (isOutside) {
33660a96aa3bSJed Brown             PetscInt f = -1;
33670a96aa3bSJed Brown 
33680a96aa3bSJed Brown             if (nq.x < 0) {
33690a96aa3bSJed Brown               f = 0;
33700a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33710a96aa3bSJed Brown               f = 1;
33720a96aa3bSJed Brown             } else if (nq.y < 0) {
33730a96aa3bSJed Brown               f = 2;
33740a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33750a96aa3bSJed Brown               f = 3;
33760a96aa3bSJed Brown   #if defined(P4_TO_P8)
33770a96aa3bSJed Brown             } else if (nq.z < 0) {
33780a96aa3bSJed Brown               f = 4;
33790a96aa3bSJed Brown             } else {
33800a96aa3bSJed Brown               f = 5;
33810a96aa3bSJed Brown   #endif
33820a96aa3bSJed Brown             }
33830a96aa3bSJed Brown             f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33840a96aa3bSJed Brown             if (baseLabel) {
33859566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
33860a96aa3bSJed Brown             } else {
33870a96aa3bSJed Brown               val = f + fStartBase;
33880a96aa3bSJed Brown             }
33899566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33900a96aa3bSJed Brown             continue;
33910a96aa3bSJed Brown           }
33920a96aa3bSJed Brown   #if defined(P4_TO_P8)
3393792fecdfSBarry Smith           PetscCallP4estReturn(isOutside, p8est_quadrant_is_outside_edge, (&nq));
33940a96aa3bSJed Brown           if (isOutside) {
33950a96aa3bSJed Brown             /* outside edge */
33960a96aa3bSJed Brown             PetscInt e = -1;
33970a96aa3bSJed Brown 
33980a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
33990a96aa3bSJed Brown               if (nq.z < 0) {
34000a96aa3bSJed Brown                 if (nq.y < 0) {
34010a96aa3bSJed Brown                   e = 0;
34020a96aa3bSJed Brown                 } else {
34030a96aa3bSJed Brown                   e = 1;
34040a96aa3bSJed Brown                 }
34050a96aa3bSJed Brown               } else {
34060a96aa3bSJed Brown                 if (nq.y < 0) {
34070a96aa3bSJed Brown                   e = 2;
34080a96aa3bSJed Brown                 } else {
34090a96aa3bSJed Brown                   e = 3;
34100a96aa3bSJed Brown                 }
34110a96aa3bSJed Brown               }
34120a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
34130a96aa3bSJed Brown               if (nq.z < 0) {
34140a96aa3bSJed Brown                 if (nq.x < 0) {
34150a96aa3bSJed Brown                   e = 4;
34160a96aa3bSJed Brown                 } else {
34170a96aa3bSJed Brown                   e = 5;
34180a96aa3bSJed Brown                 }
34190a96aa3bSJed Brown               } else {
34200a96aa3bSJed Brown                 if (nq.x < 0) {
34210a96aa3bSJed Brown                   e = 6;
34220a96aa3bSJed Brown                 } else {
34230a96aa3bSJed Brown                   e = 7;
34240a96aa3bSJed Brown                 }
34250a96aa3bSJed Brown               }
34260a96aa3bSJed Brown             } else {
34270a96aa3bSJed Brown               if (nq.y < 0) {
34280a96aa3bSJed Brown                 if (nq.x < 0) {
34290a96aa3bSJed Brown                   e = 8;
34300a96aa3bSJed Brown                 } else {
34310a96aa3bSJed Brown                   e = 9;
34320a96aa3bSJed Brown                 }
34330a96aa3bSJed Brown               } else {
34340a96aa3bSJed Brown                 if (nq.x < 0) {
34350a96aa3bSJed Brown                   e = 10;
34360a96aa3bSJed Brown                 } else {
34370a96aa3bSJed Brown                   e = 11;
34380a96aa3bSJed Brown                 }
34390a96aa3bSJed Brown               }
34400a96aa3bSJed Brown             }
34410a96aa3bSJed Brown 
34420a96aa3bSJed Brown             e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
34430a96aa3bSJed Brown             if (baseLabel) {
34449566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, e + eStartBase, &val));
34450a96aa3bSJed Brown             } else {
34460a96aa3bSJed Brown               val = e + eStartBase;
34470a96aa3bSJed Brown             }
34489566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
34490a96aa3bSJed Brown             continue;
34500a96aa3bSJed Brown           }
34510a96aa3bSJed Brown   #endif
34520a96aa3bSJed Brown           {
34530a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
34540a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
34550a96aa3bSJed Brown 
34560a96aa3bSJed Brown             if (baseLabel) {
34579566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, v + vStartBase, &val));
34580a96aa3bSJed Brown             } else {
34590a96aa3bSJed Brown               val = v + vStartBase;
34600a96aa3bSJed Brown             }
34619566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
34620a96aa3bSJed Brown           }
34630a96aa3bSJed Brown         }
34640a96aa3bSJed Brown       }
34650a96aa3bSJed Brown     }
34660a96aa3bSJed Brown     next = next->next;
34670a96aa3bSJed Brown   }
34683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34690a96aa3bSJed Brown }
34700a96aa3bSJed Brown 
3471d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex)
3472d71ae5a4SJacob Faibussowitsch {
34730a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
34740a96aa3bSJed Brown   DM                 adapt;
34750a96aa3bSJed Brown 
34760a96aa3bSJed Brown   PetscFunctionBegin;
34773ba16761SJacob Faibussowitsch   if (pforest->labelsFinalized) PetscFunctionReturn(PETSC_SUCCESS);
34780a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
34799566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
34800a96aa3bSJed Brown   if (!adapt) {
34810a96aa3bSJed Brown     /* Initialize labels from the base dm */
34829566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsInitialize(dm, plex));
34830a96aa3bSJed Brown   } else {
34840a96aa3bSJed Brown     PetscInt    dofPerDim[4] = {1, 1, 1, 1};
34850a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
34860a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
34870a96aa3bSJed Brown     PetscInt   *values, *adaptValues;
34880a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
34890a96aa3bSJed Brown     DMLabel     adaptLabel;
34900a96aa3bSJed Brown     DM          adaptPlex;
34910a96aa3bSJed Brown 
34929566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm, &adaptLabel));
34939566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(adapt, &adaptPlex));
34949566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF(adapt, dm, dofPerDim, &transferForward, &transferBackward));
34959566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &pStart, &pEnd));
34969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(adaptPlex, &pStartA, &pEndA));
34979566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEnd - pStart, &values, pEndA - pStartA, &adaptValues));
34989566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex, &pointSF));
34990a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
35000a96aa3bSJed Brown       PetscInt p;
35010a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p - pStartA] = -1;
35020a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p - pStart] = -2;
35030a96aa3bSJed Brown       if (transferForward) {
35049566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
35059566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
35060a96aa3bSJed Brown       }
35070a96aa3bSJed Brown       if (transferBackward) {
350857168dbeSPierre Jolivet         PetscCall(PetscSFReduceBegin(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
350957168dbeSPierre Jolivet         PetscCall(PetscSFReduceEnd(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35100a96aa3bSJed Brown       }
35110a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35120a96aa3bSJed Brown         PetscInt q = p, parent;
35130a96aa3bSJed Brown 
35149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35150a96aa3bSJed Brown         while (parent != q) {
35160a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
35170a96aa3bSJed Brown           q = parent;
35189566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35190a96aa3bSJed Brown         }
35200a96aa3bSJed Brown       }
352157168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, values, values, MPI_MAX));
352257168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, values, values, MPI_MAX));
35239566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35249566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, values, values, MPI_REPLACE));
3525ad540459SPierre Jolivet       for (p = pStart; p < pEnd; p++) PetscCheck(values[p - pStart] != -2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "uncovered point %" PetscInt_FMT, p);
35260a96aa3bSJed Brown     }
35270a96aa3bSJed Brown     while (next) {
35280a96aa3bSJed Brown       DMLabel     nextLabel = next->label;
35290a96aa3bSJed Brown       const char *name;
35300a96aa3bSJed Brown       PetscBool   isDepth, isCellType, isGhost, isVTK;
35310a96aa3bSJed Brown       DMLabel     label;
35320a96aa3bSJed Brown       PetscInt    p;
35330a96aa3bSJed Brown 
35349566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)nextLabel, &name));
35359566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isDepth));
35360a96aa3bSJed Brown       if (isDepth) {
35370a96aa3bSJed Brown         next = next->next;
35380a96aa3bSJed Brown         continue;
35390a96aa3bSJed Brown       }
35409566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "celltype", &isCellType));
35410a96aa3bSJed Brown       if (isCellType) {
35420a96aa3bSJed Brown         next = next->next;
35430a96aa3bSJed Brown         continue;
35440a96aa3bSJed Brown       }
35459566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "ghost", &isGhost));
35460a96aa3bSJed Brown       if (isGhost) {
35470a96aa3bSJed Brown         next = next->next;
35480a96aa3bSJed Brown         continue;
35490a96aa3bSJed Brown       }
35509566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "vtk", &isVTK));
35510a96aa3bSJed Brown       if (isVTK) {
35520a96aa3bSJed Brown         next = next->next;
35530a96aa3bSJed Brown         continue;
35540a96aa3bSJed Brown       }
35550a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
35560a96aa3bSJed Brown         next = next->next;
35570a96aa3bSJed Brown         continue;
35580a96aa3bSJed Brown       }
35590a96aa3bSJed Brown       /* label was created earlier */
35609566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
356148a46eb9SPierre Jolivet       for (p = pStartA; p < pEndA; p++) PetscCall(DMLabelGetValue(nextLabel, p, &adaptValues[p]));
35620a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
35630a96aa3bSJed Brown 
35641baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastBegin(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
356557168dbeSPierre Jolivet       if (transferBackward) PetscCall(PetscSFReduceBegin(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35661baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastEnd(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
356757168dbeSPierre Jolivet       if (transferBackward) PetscCall(PetscSFReduceEnd(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35680a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35690a96aa3bSJed Brown         PetscInt q = p, parent;
35700a96aa3bSJed Brown 
35719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35720a96aa3bSJed Brown         while (parent != q) {
35730a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
35740a96aa3bSJed Brown           q = parent;
35759566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35760a96aa3bSJed Brown         }
35770a96aa3bSJed Brown       }
357857168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, values, values, MPI_MAX));
357957168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, values, values, MPI_MAX));
35809566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35819566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35820a96aa3bSJed Brown 
358348a46eb9SPierre Jolivet       for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(label, p, values[p]));
35840a96aa3bSJed Brown       next = next->next;
35850a96aa3bSJed Brown     }
35869566063dSJacob Faibussowitsch     PetscCall(PetscFree2(values, adaptValues));
35879566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferForward));
35889566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferBackward));
35890a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
35900a96aa3bSJed Brown   }
35913ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35920a96aa3bSJed Brown }
35930a96aa3bSJed Brown 
3594d71ae5a4SJacob 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)
3595d71ae5a4SJacob Faibussowitsch {
35960a96aa3bSJed Brown   PetscInt     closureSize, c, coordStart, coordEnd, coordDim;
35970a96aa3bSJed Brown   PetscInt    *closure = NULL;
35980a96aa3bSJed Brown   PetscSection coordSec;
35990a96aa3bSJed Brown 
36000a96aa3bSJed Brown   PetscFunctionBegin;
36019566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &coordSec));
36029566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSec, &coordStart, &coordEnd));
36039566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(plex, &coordDim));
36049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(plex, cell, PETSC_TRUE, &closureSize, &closure));
36050a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
36060a96aa3bSJed Brown     PetscInt point = closure[2 * c];
36070a96aa3bSJed Brown 
36080a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
36090a96aa3bSJed Brown       PetscInt dof, off;
36100a96aa3bSJed Brown       PetscInt nCoords, i;
36119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec, point, &dof));
361208401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not understand coordinate layout");
36130a96aa3bSJed Brown       nCoords = dof / coordDim;
36149566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec, point, &off));
36150a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
36160a96aa3bSJed Brown         PetscScalar *coord               = &coords[off + i * coordDim];
36170a96aa3bSJed Brown         double       coordP4est[3]       = {0.};
36180a96aa3bSJed Brown         double       coordP4estMapped[3] = {0.};
36190a96aa3bSJed Brown         PetscInt     j;
36200a96aa3bSJed Brown         PetscReal    treeCoords[P4EST_CHILDREN][3] = {{0.}};
36210a96aa3bSJed Brown         PetscReal    eta[3]                        = {0.};
36220a96aa3bSJed Brown         PetscInt     numRounds                     = 10;
36230a96aa3bSJed Brown         PetscReal    coordGuess[3]                 = {0.};
36240a96aa3bSJed Brown 
36250a96aa3bSJed Brown         eta[0] = (PetscReal)q->x / (PetscReal)P4EST_ROOT_LEN;
36260a96aa3bSJed Brown         eta[1] = (PetscReal)q->y / (PetscReal)P4EST_ROOT_LEN;
36270a96aa3bSJed Brown   #if defined(P4_TO_P8)
36280a96aa3bSJed Brown         eta[2] = (PetscReal)q->z / (PetscReal)P4EST_ROOT_LEN;
36290a96aa3bSJed Brown   #endif
36300a96aa3bSJed Brown 
36310a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
36320a96aa3bSJed Brown           PetscInt k;
36330a96aa3bSJed Brown 
36340a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
36350a96aa3bSJed Brown         }
36360a96aa3bSJed Brown 
36370a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
36380a96aa3bSJed Brown           PetscInt  k;
36390a96aa3bSJed Brown           PetscReal prod = 1.;
36400a96aa3bSJed Brown 
36410a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
36420a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
36430a96aa3bSJed Brown         }
36440a96aa3bSJed Brown 
36450a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
36460a96aa3bSJed Brown           PetscInt dir;
36470a96aa3bSJed Brown 
36480a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
36490a96aa3bSJed Brown             PetscInt  k;
36500a96aa3bSJed Brown             PetscReal diff[3];
36510a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
36520a96aa3bSJed Brown             PetscReal rhs, scale, update;
36530a96aa3bSJed Brown 
36540a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
36550a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
36560a96aa3bSJed Brown               PetscInt  l;
36570a96aa3bSJed Brown               PetscReal prod = 1.;
36580a96aa3bSJed Brown 
36590a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
36600a96aa3bSJed Brown                 if (l == dir) {
36610a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? 1. : -1.;
36620a96aa3bSJed Brown                 } else {
36630a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
36640a96aa3bSJed Brown                 }
36650a96aa3bSJed Brown               }
36660a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
36670a96aa3bSJed Brown             }
36680a96aa3bSJed Brown             rhs   = 0.;
36690a96aa3bSJed Brown             scale = 0;
36700a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
36710a96aa3bSJed Brown               rhs += diff[k] * dXdeta[k];
36720a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
36730a96aa3bSJed Brown             }
36740a96aa3bSJed Brown             update = rhs / scale;
36750a96aa3bSJed Brown             eta[dir] += update;
36760a96aa3bSJed Brown             eta[dir] = PetscMin(eta[dir], 1.);
36770a96aa3bSJed Brown             eta[dir] = PetscMax(eta[dir], 0.);
36780a96aa3bSJed Brown 
36790a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
36800a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
36810a96aa3bSJed Brown               PetscInt  l;
36820a96aa3bSJed Brown               PetscReal prod = 1.;
36830a96aa3bSJed Brown 
36840a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
36850a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
36860a96aa3bSJed Brown             }
36870a96aa3bSJed Brown           }
36880a96aa3bSJed Brown         }
36890a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double)eta[j];
36900a96aa3bSJed Brown 
36910a96aa3bSJed Brown         if (geom) {
36920a96aa3bSJed Brown           (geom->X)(geom, t, coordP4est, coordP4estMapped);
36930a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar)coordP4estMapped[j];
36940a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not coded");
36950a96aa3bSJed Brown       }
36960a96aa3bSJed Brown     }
36970a96aa3bSJed Brown   }
36989566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(plex, cell, PETSC_TRUE, &closureSize, &closure));
36993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
37000a96aa3bSJed Brown }
37010a96aa3bSJed Brown 
3702d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex)
3703d71ae5a4SJacob Faibussowitsch {
37040a96aa3bSJed Brown   DM_Forest         *forest;
37050a96aa3bSJed Brown   DM_Forest_pforest *pforest;
37060a96aa3bSJed Brown   p4est_geometry_t  *geom;
37070a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd;
37080a96aa3bSJed Brown   Vec                coordLocalVec;
37090a96aa3bSJed Brown   PetscScalar       *coords;
37100a96aa3bSJed Brown   p4est_topidx_t     flt, llt, t;
37110a96aa3bSJed Brown   p4est_tree_t      *trees;
37120a96aa3bSJed Brown   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
37130a96aa3bSJed Brown   void *mapCtx;
37140a96aa3bSJed Brown 
37150a96aa3bSJed Brown   PetscFunctionBegin;
37160a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
37170a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
37180a96aa3bSJed Brown   geom    = pforest->topo->geom;
37199566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
37203ba16761SJacob Faibussowitsch   if (!geom && !map) PetscFunctionReturn(PETSC_SUCCESS);
37219566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex, &coordLocalVec));
37229566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordLocalVec, &coords));
37230a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
37240a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
37250a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
37260a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
37270a96aa3bSJed Brown   trees       = (p4est_tree_t *)pforest->forest->trees->array;
37280a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
37290a96aa3bSJed Brown     PetscSection coordSec;
37300a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
37310a96aa3bSJed Brown     DM           base;
37320a96aa3bSJed Brown 
37339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
37342827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
37350a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
37369566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm, &base));
37379566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(plex, &coordSec));
37389566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(coordSec, &coordStart, &coordEnd));
37399566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(plex, &coordDim));
37400a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim, 3);
37410a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
37420a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
37430a96aa3bSJed Brown       PetscInt  dof, off, cell = -1, coarsePoint = -1;
37440a96aa3bSJed Brown       PetscInt  nCoords, i;
37459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec, p, &dof));
374608401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not understand coordinate layout");
37470a96aa3bSJed Brown       nCoords = dof / coordDim;
37489566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec, p, &off));
37499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
37500a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
37510a96aa3bSJed Brown         PetscInt point = star[2 * i];
37520a96aa3bSJed Brown 
37530a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
37540a96aa3bSJed Brown           cell = point;
37550a96aa3bSJed Brown           break;
37560a96aa3bSJed Brown         }
37570a96aa3bSJed Brown       }
37589566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
37590a96aa3bSJed Brown       if (cell >= 0) {
37600a96aa3bSJed Brown         if (cell < cLocalStart) {
37610a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37620a96aa3bSJed Brown 
37630a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
37640a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
37650a96aa3bSJed Brown           cell -= cLocalStart;
37660a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
37670a96aa3bSJed Brown             p4est_tree_t *tree = &(trees[t]);
37680a96aa3bSJed Brown 
37690a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t)cell < tree->quadrants_offset + tree->quadrants.elem_count) {
37700a96aa3bSJed Brown               coarsePoint = t;
37710a96aa3bSJed Brown               break;
37720a96aa3bSJed Brown             }
37730a96aa3bSJed Brown           }
37740a96aa3bSJed Brown         } else {
37750a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37760a96aa3bSJed Brown 
37770a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
37780a96aa3bSJed Brown         }
37790a96aa3bSJed Brown       }
37800a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
37810a96aa3bSJed Brown         PetscScalar *coord               = &coords[off + i * coordDim];
37820a96aa3bSJed Brown         PetscReal    coordP4est[3]       = {0.};
37830a96aa3bSJed Brown         PetscReal    coordP4estMapped[3] = {0.};
37840a96aa3bSJed Brown         PetscInt     j;
37850a96aa3bSJed Brown 
37860a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
37879566063dSJacob Faibussowitsch         PetscCall((map)(base, coarsePoint, p4estCoordDim, coordP4est, coordP4estMapped, mapCtx));
37880a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar)coordP4estMapped[j];
37890a96aa3bSJed Brown       }
37900a96aa3bSJed Brown     }
37910a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
37920a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
37930a96aa3bSJed Brown 
37949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
37952827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
37960a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
37970a96aa3bSJed Brown     if (cLocalStart > 0) {
37980a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37990a96aa3bSJed Brown       PetscInt          count;
38000a96aa3bSJed Brown 
38010a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
38020a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
38030a96aa3bSJed Brown         p4est_topidx_t    t    = quad->p.which_tree;
38040a96aa3bSJed Brown 
38059566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count, quad, t, pforest->topo->conn, coords));
38060a96aa3bSJed Brown       }
38070a96aa3bSJed Brown     }
38080a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
38090a96aa3bSJed Brown       p4est_tree_t     *tree     = &(trees[t]);
38100a96aa3bSJed Brown       PetscInt          offset   = cLocalStart + tree->quadrants_offset, i;
38110a96aa3bSJed Brown       PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
38120a96aa3bSJed Brown       p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
38130a96aa3bSJed Brown 
38140a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
38150a96aa3bSJed Brown         PetscInt count = i + offset;
38160a96aa3bSJed Brown 
38179566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count, &quads[i], t, pforest->topo->conn, coords));
38180a96aa3bSJed Brown       }
38190a96aa3bSJed Brown     }
38200a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
38210a96aa3bSJed Brown       p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
38220a96aa3bSJed Brown       PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
38230a96aa3bSJed Brown       PetscInt          count;
38240a96aa3bSJed Brown 
38250a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
38260a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
38270a96aa3bSJed Brown         p4est_topidx_t    t    = quad->p.which_tree;
38280a96aa3bSJed Brown 
38299566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count + cLocalEnd, quad, t, pforest->topo->conn, coords));
38300a96aa3bSJed Brown       }
38310a96aa3bSJed Brown     }
38320a96aa3bSJed Brown   }
38339566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordLocalVec, &coords));
38343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38350a96aa3bSJed Brown }
38360a96aa3bSJed Brown 
3837d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestQuadrantIsInterior(p4est_quadrant_t *quad, PetscBool *is_interior)
3838d71ae5a4SJacob Faibussowitsch {
3839852b71a7SToby Isaac   PetscFunctionBegin;
3840852b71a7SToby Isaac   p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3841852b71a7SToby Isaac   if ((quad->x > 0) && (quad->x + h < P4EST_ROOT_LEN)
3842852b71a7SToby Isaac   #ifdef P4_TO_P8
3843852b71a7SToby Isaac       && (quad->z > 0) && (quad->z + h < P4EST_ROOT_LEN)
3844852b71a7SToby Isaac   #endif
3845852b71a7SToby Isaac       && (quad->y > 0) && (quad->y + h < P4EST_ROOT_LEN)) {
3846852b71a7SToby Isaac     *is_interior = PETSC_TRUE;
3847852b71a7SToby Isaac   } else {
3848852b71a7SToby Isaac     *is_interior = PETSC_FALSE;
3849852b71a7SToby Isaac   }
38503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3851852b71a7SToby Isaac }
3852852b71a7SToby Isaac 
3853852b71a7SToby Isaac /* We always use DG coordinates with p4est: if they do not match the vertex
3854852b71a7SToby Isaac    coordinates, add space for them in the section */
3855d71ae5a4SJacob 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)
3856d71ae5a4SJacob Faibussowitsch {
3857852b71a7SToby Isaac   PetscBool is_interior;
3858852b71a7SToby Isaac 
3859852b71a7SToby Isaac   PetscFunctionBegin;
3860852b71a7SToby Isaac   PetscCall(PforestQuadrantIsInterior(quad, &is_interior));
3861852b71a7SToby Isaac   if (is_interior) { // quads in the interior of a coarse cell can't touch periodic interfaces
3862852b71a7SToby Isaac     PetscCall(PetscSectionSetDof(newSection, cell, 0));
3863852b71a7SToby Isaac     PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3864852b71a7SToby Isaac   } else {
3865852b71a7SToby Isaac     PetscInt     cSize;
3866852b71a7SToby Isaac     PetscScalar *values      = NULL;
3867852b71a7SToby Isaac     PetscBool    same_coords = PETSC_TRUE;
3868852b71a7SToby Isaac 
3869852b71a7SToby Isaac     PetscCall(DMPlexVecGetClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3870852b71a7SToby Isaac     PetscAssert(cSize == cDim * P4EST_CHILDREN, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected closure size");
3871852b71a7SToby Isaac     for (int c = 0; c < P4EST_CHILDREN; c++) {
3872852b71a7SToby Isaac       p4est_qcoord_t quad_coords[3];
3873852b71a7SToby Isaac       p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3874852b71a7SToby Isaac       double         corner_coords[3];
3875852b71a7SToby Isaac       double         vert_coords[3];
3876852b71a7SToby Isaac       PetscInt       corner = PetscVertToP4estVert[c];
3877852b71a7SToby Isaac 
3878ad540459SPierre Jolivet       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) vert_coords[d] = PetscRealPart(values[c * cDim + d]);
3879852b71a7SToby Isaac 
3880852b71a7SToby Isaac       quad_coords[0] = quad->x;
3881852b71a7SToby Isaac       quad_coords[1] = quad->y;
3882852b71a7SToby Isaac   #ifdef P4_TO_P8
3883852b71a7SToby Isaac       quad_coords[2] = quad->z;
3884852b71a7SToby Isaac   #endif
3885ad540459SPierre Jolivet       for (int d = 0; d < 3; d++) quad_coords[d] += (corner & (1 << d)) ? h : 0;
3886852b71a7SToby Isaac   #ifndef P4_TO_P8
3887648bc8c4SBarry Smith       PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3888852b71a7SToby Isaac   #else
3889648bc8c4SBarry Smith       PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3890852b71a7SToby Isaac   #endif
3891852b71a7SToby Isaac       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
3892852b71a7SToby Isaac         if (fabs(vert_coords[d] - corner_coords[d]) > PETSC_SMALL) {
3893852b71a7SToby Isaac           same_coords = PETSC_FALSE;
3894852b71a7SToby Isaac           break;
3895852b71a7SToby Isaac         }
3896852b71a7SToby Isaac       }
3897852b71a7SToby Isaac     }
3898852b71a7SToby Isaac     if (same_coords) {
3899852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, 0));
3900852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3901852b71a7SToby Isaac     } else {
3902852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, cSize));
3903852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, cSize));
3904852b71a7SToby Isaac     }
3905852b71a7SToby Isaac     PetscCall(DMPlexVecRestoreClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3906852b71a7SToby Isaac   }
39073ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3908852b71a7SToby Isaac }
3909852b71a7SToby Isaac 
3910d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestLocalizeCell(DM plex, PetscInt cDim, DM_Forest_pforest *pforest, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad, PetscScalar coords[])
3911d71ae5a4SJacob Faibussowitsch {
3912852b71a7SToby Isaac   PetscInt cdof, off;
3913852b71a7SToby Isaac 
3914852b71a7SToby Isaac   PetscFunctionBegin;
3915852b71a7SToby Isaac   PetscCall(PetscSectionGetDof(newSection, cell, &cdof));
39163ba16761SJacob Faibussowitsch   if (!cdof) PetscFunctionReturn(PETSC_SUCCESS);
3917852b71a7SToby Isaac 
3918852b71a7SToby Isaac   PetscCall(PetscSectionGetOffset(newSection, cell, &off));
3919852b71a7SToby Isaac   for (PetscInt c = 0, pos = off; c < P4EST_CHILDREN; c++) {
3920852b71a7SToby Isaac     p4est_qcoord_t quad_coords[3];
3921852b71a7SToby Isaac     p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3922852b71a7SToby Isaac     double         corner_coords[3];
3923852b71a7SToby Isaac     PetscInt       corner = PetscVertToP4estVert[c];
3924852b71a7SToby Isaac 
3925852b71a7SToby Isaac     quad_coords[0] = quad->x;
3926852b71a7SToby Isaac     quad_coords[1] = quad->y;
3927852b71a7SToby Isaac   #ifdef P4_TO_P8
3928852b71a7SToby Isaac     quad_coords[2] = quad->z;
3929852b71a7SToby Isaac   #endif
3930ad540459SPierre Jolivet     for (int d = 0; d < 3; d++) quad_coords[d] += (corner & (1 << d)) ? h : 0;
3931852b71a7SToby Isaac   #ifndef P4_TO_P8
3932648bc8c4SBarry Smith     PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3933852b71a7SToby Isaac   #else
3934648bc8c4SBarry Smith     PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3935852b71a7SToby Isaac   #endif
3936ad540459SPierre Jolivet     for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) coords[pos++] = corner_coords[d];
3937ad540459SPierre Jolivet     for (PetscInt d = PetscMin(cDim, 3); d < cDim; d++) coords[pos++] = 0.;
3938852b71a7SToby Isaac   }
39393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3940852b71a7SToby Isaac }
3941852b71a7SToby Isaac 
3942d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
3943d71ae5a4SJacob Faibussowitsch {
39440a96aa3bSJed Brown   DM_Forest         *forest;
39450a96aa3bSJed Brown   DM_Forest_pforest *pforest;
39466858538eSMatthew G. Knepley   DM                 base, cdm, cdmCell;
3947852b71a7SToby Isaac   Vec                cVec, cVecOld;
3948852b71a7SToby Isaac   PetscSection       oldSection, newSection;
39490a96aa3bSJed Brown   PetscScalar       *coords2;
39506858538eSMatthew G. Knepley   const PetscReal   *L;
39510a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd, coarsePoint;
3952852b71a7SToby Isaac   PetscInt           cDim, newStart, newEnd;
3953852b71a7SToby Isaac   PetscInt           v, vStart, vEnd, cp, cStart, cEnd, cEndInterior;
39540a96aa3bSJed Brown   p4est_topidx_t     flt, llt, t;
39550a96aa3bSJed Brown   p4est_tree_t      *trees;
39566858538eSMatthew G. Knepley   PetscBool          baseLocalized = PETSC_FALSE;
39570a96aa3bSJed Brown 
39580a96aa3bSJed Brown   PetscFunctionBegin;
39594fb89dddSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dm, NULL, NULL, &L));
39600a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
39619566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cDim));
39629566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
39636858538eSMatthew G. Knepley   if (base) PetscCall(DMGetCoordinatesLocalized(base, &baseLocalized));
39640a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
39653ba16761SJacob Faibussowitsch   if (!baseLocalized && !L) PetscFunctionReturn(PETSC_SUCCESS);
39669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &newStart, &newEnd));
39670a96aa3bSJed Brown 
39689566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newSection));
39699566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(newSection, 1));
39709566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim));
39719566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSection, newStart, newEnd));
39720a96aa3bSJed Brown 
39739566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &oldSection));
39749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
3975852b71a7SToby Isaac   PetscCall(DMGetCoordinatesLocal(plex, &cVecOld));
39760a96aa3bSJed Brown 
39770a96aa3bSJed Brown   forest      = (DM_Forest *)dm->data;
39780a96aa3bSJed Brown   pforest     = (DM_Forest_pforest *)forest->data;
39790a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
39800a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
39810a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
39820a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
39830a96aa3bSJed Brown   trees       = (p4est_tree_t *)pforest->forest->trees->array;
39840a96aa3bSJed Brown 
39859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
39862827ebadSStefano Zampini   PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
39870a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
3988852b71a7SToby Isaac   cp   = 0;
39890a96aa3bSJed Brown   if (cLocalStart > 0) {
39900a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
3991852b71a7SToby Isaac     PetscInt          cell;
39920a96aa3bSJed Brown 
3993852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
3994852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
3995852b71a7SToby Isaac 
39960a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
3997852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
39980a96aa3bSJed Brown     }
39990a96aa3bSJed Brown   }
40000a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
40010a96aa3bSJed Brown     p4est_tree_t     *tree     = &(trees[t]);
40020a96aa3bSJed Brown     PetscInt          offset   = cLocalStart + tree->quadrants_offset;
40030a96aa3bSJed Brown     PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
4004852b71a7SToby Isaac     p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
40050a96aa3bSJed Brown     PetscInt          i;
40060a96aa3bSJed Brown 
40070a96aa3bSJed Brown     if (!numQuads) continue;
40080a96aa3bSJed Brown     coarsePoint = t;
4009852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4010852b71a7SToby Isaac       PetscInt          cell = i + offset;
4011852b71a7SToby Isaac       p4est_quadrant_t *quad = &quads[i];
40120a96aa3bSJed Brown 
4013852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
40140a96aa3bSJed Brown     }
40150a96aa3bSJed Brown   }
40160a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
40170a96aa3bSJed Brown     p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
40180a96aa3bSJed Brown     PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
40190a96aa3bSJed Brown     PetscInt          count;
40200a96aa3bSJed Brown 
4021852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
40220a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
40230a96aa3bSJed Brown       coarsePoint            = quad->p.which_tree;
4024852b71a7SToby Isaac       PetscInt cell          = count + cLocalEnd;
40250a96aa3bSJed Brown 
4026852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
40270a96aa3bSJed Brown     }
40280a96aa3bSJed Brown   }
4029852b71a7SToby Isaac   PetscAssert(cp == cEnd - cStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT, cp, cEnd - cStart);
40300a96aa3bSJed Brown 
40319566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSection));
40326858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(plex, &cdm));
40336858538eSMatthew G. Knepley   PetscCall(DMClone(cdm, &cdmCell));
40346858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(plex, cdmCell));
40356858538eSMatthew G. Knepley   PetscCall(DMDestroy(&cdmCell));
40366858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateSection(plex, cDim, newSection));
40379566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &v));
40389566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
40399566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)cVec, "coordinates"));
40409566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(cVec, cDim));
40419566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE));
40429566063dSJacob Faibussowitsch   PetscCall(VecSetType(cVec, VECSTANDARD));
40439566063dSJacob Faibussowitsch   PetscCall(VecSet(cVec, PETSC_MIN_REAL));
40440a96aa3bSJed Brown 
40450a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
40466858538eSMatthew G. Knepley   PetscCall(VecGetArray(cVec, &coords2));
4047852b71a7SToby Isaac   cp = 0;
4048852b71a7SToby Isaac   if (cLocalStart > 0) {
4049852b71a7SToby Isaac     p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
4050852b71a7SToby Isaac     PetscInt          cell;
4051852b71a7SToby Isaac 
4052852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
4053852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
4054852b71a7SToby Isaac 
4055852b71a7SToby Isaac       coarsePoint = quad->p.which_tree;
4056852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4057852b71a7SToby Isaac     }
4058852b71a7SToby Isaac   }
40590a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
40600a96aa3bSJed Brown     p4est_tree_t     *tree     = &(trees[t]);
40610a96aa3bSJed Brown     PetscInt          offset   = cLocalStart + tree->quadrants_offset;
40620a96aa3bSJed Brown     PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
4063852b71a7SToby Isaac     p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
4064852b71a7SToby Isaac     PetscInt          i;
40650a96aa3bSJed Brown 
40660a96aa3bSJed Brown     if (!numQuads) continue;
4067852b71a7SToby Isaac     coarsePoint = t;
4068852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4069852b71a7SToby Isaac       PetscInt          cell = i + offset;
40700a96aa3bSJed Brown       p4est_quadrant_t *quad = &quads[i];
40710a96aa3bSJed Brown 
4072852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4073852b71a7SToby Isaac     }
4074852b71a7SToby Isaac   }
4075852b71a7SToby Isaac   if (cLocalEnd - cLocalStart < cEnd - cStart) {
4076852b71a7SToby Isaac     p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
4077852b71a7SToby Isaac     PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
4078852b71a7SToby Isaac     PetscInt          count;
40790a96aa3bSJed Brown 
4080852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
4081852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
4082852b71a7SToby Isaac       coarsePoint            = quad->p.which_tree;
4083852b71a7SToby Isaac       PetscInt cell          = count + cLocalEnd;
40840a96aa3bSJed Brown 
4085852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
40860a96aa3bSJed Brown     }
40870a96aa3bSJed Brown   }
40889566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cVec, &coords2));
40896858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(plex, cVec));
40909566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cVec));
40919566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&newSection));
40923ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40930a96aa3bSJed Brown }
40940a96aa3bSJed Brown 
40950a96aa3bSJed Brown   #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
4096d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
4097d71ae5a4SJacob Faibussowitsch {
40980a96aa3bSJed Brown   DM_Forest         *forest;
40990a96aa3bSJed Brown   DM_Forest_pforest *pforest;
41000a96aa3bSJed Brown 
41010a96aa3bSJed Brown   PetscFunctionBegin;
41020a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
41030a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
41049566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointAdaptToSelfSF)));
41059566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointSelfToAdaptSF)));
41069566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
41079566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
41083ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41090a96aa3bSJed Brown }
41100a96aa3bSJed Brown 
4111d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
4112d71ae5a4SJacob Faibussowitsch {
41130a96aa3bSJed Brown   DM_Forest           *forest;
41140a96aa3bSJed Brown   DM_Forest_pforest   *pforest;
41150a96aa3bSJed Brown   DM                   refTree, newPlex, base;
41160a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
41170a96aa3bSJed Brown   MPI_Comm             comm;
41180a96aa3bSJed Brown   PetscBool            isPforest;
41190a96aa3bSJed Brown   PetscInt             dim;
41200a96aa3bSJed Brown   PetscInt             overlap;
41210a96aa3bSJed Brown   p4est_connect_type_t ctype;
41220a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
41230a96aa3bSJed Brown   sc_array_t          *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
41240a96aa3bSJed Brown   PetscSection         parentSection;
41250a96aa3bSJed Brown   PetscSF              pointSF;
41260a96aa3bSJed Brown   size_t               zz, count;
41270a96aa3bSJed Brown   PetscInt             pStart, pEnd;
41280a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
41290a96aa3bSJed Brown 
41300a96aa3bSJed Brown   PetscFunctionBegin;
41310a96aa3bSJed Brown 
41320a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41330a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
41349566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPFOREST, &isPforest));
413528b400f6SJacob Faibussowitsch   PetscCheck(isPforest, comm, PETSC_ERR_ARG_WRONG, "Expected DM type %s, got %s", DMPFOREST, ((PetscObject)dm)->type_name);
41369566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
413763a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Expected DM dimension %d, got %" PetscInt_FMT, P4EST_DIM, dim);
41380a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
41390a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
41409566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
414148a46eb9SPierre Jolivet   if (base) PetscCall(DMGetLabel(base, "ghost", &ghostLabelBase));
41420a96aa3bSJed Brown   if (!pforest->plex) {
41430a96aa3bSJed Brown     PetscMPIInt size;
41440a96aa3bSJed Brown 
41459566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
41469566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm, &newPlex));
41479566063dSJacob Faibussowitsch     PetscCall(DMSetType(newPlex, DMPLEX));
41489566063dSJacob Faibussowitsch     PetscCall(DMSetMatType(newPlex, dm->mattype));
41490a96aa3bSJed Brown     /* share labels */
41509566063dSJacob Faibussowitsch     PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
41519566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
41529566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
41539566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
41540a96aa3bSJed Brown     if (adjDim == 0) {
41550a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
41560a96aa3bSJed Brown     } else if (adjCodim == 1) {
41570a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
41580a96aa3bSJed Brown   #if defined(P4_TO_P8)
41590a96aa3bSJed Brown     } else if (adjDim == 1) {
41600a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
41610a96aa3bSJed Brown   #endif
41620a96aa3bSJed Brown     } else {
416363a3b9bcSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid adjacency dimension %" PetscInt_FMT, adjDim);
41640a96aa3bSJed Brown     }
416563a3b9bcSJacob 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);
41669566063dSJacob Faibussowitsch     PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
416760667520SVaclav Hapla     PetscCall(DMPlexSetOverlap_Plex(newPlex, NULL, overlap));
41680a96aa3bSJed Brown 
41690a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
41700a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
41710a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
41720a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
41730a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
41740a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
41750a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
41760a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
41770a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
41780a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
41790a96aa3bSJed Brown 
4180792fecdfSBarry 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));
41810a96aa3bSJed Brown 
41820a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt)first_local_quad;
41830a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt)pforest->forest->local_num_quadrants;
41849566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
41859566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
41869566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
41879566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
41889566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, coordDim));
41899566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(children));
41909566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(parents));
41919566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(childids));
41929566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(leaves));
41939566063dSJacob Faibussowitsch     PetscCall(locidx_pair_to_PetscSFNode(remotes));
41940a96aa3bSJed Brown 
41959566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(newPlex, P4EST_DIM));
41969566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDim(newPlex, coordDim));
41979566063dSJacob Faibussowitsch     PetscCall(DMPlexSetMaxProjectionHeight(newPlex, P4EST_DIM - 1));
41989566063dSJacob 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));
41999566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(newPlex));
42009566063dSJacob Faibussowitsch     PetscCall(DMCreateReferenceTree_pforest(comm, &refTree));
42019566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(newPlex, refTree));
42029566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(comm, &parentSection));
42039566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(newPlex, &pStart, &pEnd));
42049566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
42050a96aa3bSJed Brown     count = children->elem_count;
42060a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
42070a96aa3bSJed Brown       PetscInt child = *((PetscInt *)sc_array_index(children, zz));
42080a96aa3bSJed Brown 
42099566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(parentSection, child, 1));
42100a96aa3bSJed Brown     }
42119566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
42129566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(newPlex, parentSection, (PetscInt *)parents->array, (PetscInt *)childids->array));
42139566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&parentSection));
42149566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &pointSF));
42150a96aa3bSJed Brown     /*
42160a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
42170a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
42180a96aa3bSJed Brown     */
42199566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(pointSF, pEnd - pStart, (PetscInt)leaves->elem_count, (PetscInt *)leaves->array, PETSC_COPY_VALUES, (PetscSFNode *)remotes->array, PETSC_COPY_VALUES));
42209566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(newPlex, pointSF));
42219566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(dm, pointSF));
42220a96aa3bSJed Brown     {
42230a96aa3bSJed Brown       DM coordDM;
42240a96aa3bSJed Brown 
42259566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex, &coordDM));
42269566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(coordDM, pointSF));
42270a96aa3bSJed Brown     }
42289566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointSF));
42290a96aa3bSJed Brown     sc_array_destroy(points_per_dim);
42300a96aa3bSJed Brown     sc_array_destroy(cone_sizes);
42310a96aa3bSJed Brown     sc_array_destroy(cones);
42320a96aa3bSJed Brown     sc_array_destroy(cone_orientations);
42330a96aa3bSJed Brown     sc_array_destroy(coords);
42340a96aa3bSJed Brown     sc_array_destroy(children);
42350a96aa3bSJed Brown     sc_array_destroy(parents);
42360a96aa3bSJed Brown     sc_array_destroy(childids);
42370a96aa3bSJed Brown     sc_array_destroy(leaves);
42380a96aa3bSJed Brown     sc_array_destroy(remotes);
42390a96aa3bSJed Brown 
42400a96aa3bSJed Brown     {
42414fb89dddSMatthew G. Knepley       const PetscReal *maxCell, *Lstart, *L;
42420a96aa3bSJed Brown 
42434fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
42444fb89dddSMatthew G. Knepley       PetscCall(DMSetPeriodicity(newPlex, maxCell, Lstart, L));
42459566063dSJacob Faibussowitsch       PetscCall(DMPforestLocalizeCoordinates(dm, newPlex));
42460a96aa3bSJed Brown     }
42470a96aa3bSJed Brown 
42480a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
42490a96aa3bSJed Brown       Vec                coordsGlobal, coordsLocal;
42500a96aa3bSJed Brown       const PetscScalar *globalArray;
42510a96aa3bSJed Brown       PetscScalar       *localArray;
42520a96aa3bSJed Brown       PetscSF            coordSF;
42530a96aa3bSJed Brown       DM                 coordDM;
42540a96aa3bSJed Brown 
42559566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex, &coordDM));
42569566063dSJacob Faibussowitsch       PetscCall(DMGetSectionSF(coordDM, &coordSF));
42579566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinates(newPlex, &coordsGlobal));
42589566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal));
42599566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordsGlobal, &globalArray));
42609566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordsLocal, &localArray));
42619566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coordSF, MPIU_SCALAR, globalArray, localArray, MPI_REPLACE));
42629566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coordSF, MPIU_SCALAR, globalArray, localArray, MPI_REPLACE));
42639566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordsLocal, &localArray));
42649566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray));
42659566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal));
42660a96aa3bSJed Brown     }
42679566063dSJacob Faibussowitsch     PetscCall(DMPforestMapCoordinates(dm, newPlex));
42680a96aa3bSJed Brown 
42690a96aa3bSJed Brown     pforest->plex = newPlex;
42700a96aa3bSJed Brown 
42710a96aa3bSJed Brown     /* copy labels */
42729566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsFinalize(dm, newPlex));
42730a96aa3bSJed Brown 
42740a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
42750a96aa3bSJed Brown       PetscInt numAdded;
42760a96aa3bSJed Brown       DM       newPlexGhosted;
42770a96aa3bSJed Brown       void    *ctx;
42780a96aa3bSJed Brown 
42799566063dSJacob Faibussowitsch       PetscCall(DMPlexConstructGhostCells(newPlex, pforest->ghostName, &numAdded, &newPlexGhosted));
42809566063dSJacob Faibussowitsch       PetscCall(DMGetApplicationContext(newPlex, &ctx));
42819566063dSJacob Faibussowitsch       PetscCall(DMSetApplicationContext(newPlexGhosted, ctx));
42820a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
42839566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(newPlexGhosted, &pointSF));
42849566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(dm, pointSF));
42859566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&newPlex));
42869566063dSJacob Faibussowitsch       PetscCall(DMPlexSetReferenceTree(newPlexGhosted, refTree));
42879566063dSJacob Faibussowitsch       PetscCall(DMForestClearAdaptivityForest_pforest(dm));
42880a96aa3bSJed Brown       newPlex = newPlexGhosted;
42890a96aa3bSJed Brown 
42900a96aa3bSJed Brown       /* share the labels back */
42919566063dSJacob Faibussowitsch       PetscCall(DMDestroyLabelLinkList_Internal(dm));
42929566063dSJacob Faibussowitsch       PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
42930a96aa3bSJed Brown       pforest->plex = newPlex;
42940a96aa3bSJed Brown     }
42959566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&refTree));
42960a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
4297d0609cedSBarry Smith       PetscObjectOptionsBegin((PetscObject)newPlex);
4298dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(newPlex, PetscOptionsObject));
4299dbbe0bcdSBarry Smith       PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)newPlex, PetscOptionsObject));
4300d0609cedSBarry Smith       PetscOptionsEnd();
43010a96aa3bSJed Brown     }
43029566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(newPlex, NULL, "-dm_p4est_plex_view"));
43030a96aa3bSJed Brown     {
43046858538eSMatthew G. Knepley       DM           cdm;
43050a96aa3bSJed Brown       PetscSection coordsSec;
43060a96aa3bSJed Brown       Vec          coords;
43070a96aa3bSJed Brown       PetscInt     cDim;
43080a96aa3bSJed Brown 
43099566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(newPlex, &cDim));
43109566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(newPlex, &coordsSec));
43119566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinateSection(dm, cDim, coordsSec));
43129566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coords));
43139566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(dm, coords));
43146858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateDM(newPlex, &cdm));
43156858538eSMatthew G. Knepley       if (cdm) PetscCall(DMSetCellCoordinateDM(dm, cdm));
43166858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateSection(newPlex, &coordsSec));
43176858538eSMatthew G. Knepley       if (coordsSec) PetscCall(DMSetCellCoordinateSection(dm, cDim, coordsSec));
43186858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinatesLocal(newPlex, &coords));
43196858538eSMatthew G. Knepley       if (coords) PetscCall(DMSetCellCoordinatesLocal(dm, coords));
43200a96aa3bSJed Brown     }
43210a96aa3bSJed Brown   }
43220a96aa3bSJed Brown   newPlex = pforest->plex;
43230a96aa3bSJed Brown   if (plex) {
43249566063dSJacob Faibussowitsch     PetscCall(DMClone(newPlex, plex));
43256858538eSMatthew G. Knepley   #if 0
43269566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43279566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDM(*plex,coordDM));
43286858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(newPlex,&coordDM));
43296858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*plex,coordDM));
43306858538eSMatthew G. Knepley   #endif
43319566063dSJacob Faibussowitsch     PetscCall(DMShareDiscretization(dm, *plex));
43320a96aa3bSJed Brown   }
43333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43340a96aa3bSJed Brown }
43350a96aa3bSJed Brown 
4336d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSetFromOptions_pforest(DM dm, PetscOptionItems *PetscOptionsObject)
4337d71ae5a4SJacob Faibussowitsch {
43380a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43390a96aa3bSJed Brown   char               stringBuffer[256];
43400a96aa3bSJed Brown   PetscBool          flg;
43410a96aa3bSJed Brown 
43420a96aa3bSJed Brown   PetscFunctionBegin;
4343dbbe0bcdSBarry Smith   PetscCall(DMSetFromOptions_Forest(dm, PetscOptionsObject));
4344d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DM" P4EST_STRING " options");
43459566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening", "partition forest to allow for coarsening", "DMP4estSetPartitionForCoarsening", pforest->partition_for_coarsening, &(pforest->partition_for_coarsening), NULL));
43469566063dSJacob 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));
4347d0609cedSBarry Smith   PetscOptionsHeadEnd();
43480a96aa3bSJed Brown   if (flg) {
43499566063dSJacob Faibussowitsch     PetscCall(PetscFree(pforest->ghostName));
43509566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(stringBuffer, &pforest->ghostName));
43510a96aa3bSJed Brown   }
43523ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43530a96aa3bSJed Brown }
43540a96aa3bSJed Brown 
43550a96aa3bSJed Brown   #if !defined(P4_TO_P8)
43560a96aa3bSJed Brown     #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
43570a96aa3bSJed Brown     #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
43580a96aa3bSJed Brown   #else
43590a96aa3bSJed Brown     #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
43600a96aa3bSJed Brown     #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
43610a96aa3bSJed Brown   #endif
43620a96aa3bSJed Brown 
4363d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
4364d71ae5a4SJacob Faibussowitsch {
43650a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43660a96aa3bSJed Brown 
43670a96aa3bSJed Brown   PetscFunctionBegin;
43680a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43690a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43700a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
43713ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43720a96aa3bSJed Brown }
43730a96aa3bSJed Brown 
4374d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
4375d71ae5a4SJacob Faibussowitsch {
43760a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43770a96aa3bSJed Brown 
43780a96aa3bSJed Brown   PetscFunctionBegin;
43790a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43800a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43810a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
43823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43830a96aa3bSJed Brown }
43840a96aa3bSJed Brown 
4385d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetPlex(DM dm, DM *plex)
4386d71ae5a4SJacob Faibussowitsch {
43870a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43880a96aa3bSJed Brown 
43890a96aa3bSJed Brown   PetscFunctionBegin;
43900a96aa3bSJed Brown   if (plex) *plex = NULL;
43919566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
43920a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
439348a46eb9SPierre Jolivet   if (!pforest->plex) PetscCall(DMConvert_pforest_plex(dm, DMPLEX, NULL));
43949566063dSJacob Faibussowitsch   PetscCall(DMShareDiscretization(dm, pforest->plex));
43950a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
43963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43970a96aa3bSJed Brown }
43980a96aa3bSJed Brown 
43990a96aa3bSJed Brown   #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
4400d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
4401d71ae5a4SJacob Faibussowitsch {
44020a96aa3bSJed Brown   PetscSection gsc, gsf;
44030a96aa3bSJed Brown   PetscInt     m, n;
44040a96aa3bSJed Brown   DM           cdm;
44050a96aa3bSJed Brown 
44060a96aa3bSJed Brown   PetscFunctionBegin;
44079566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
44089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
44099566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
44109566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
44110a96aa3bSJed Brown 
44129566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmFine), interpolation));
44139566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
44149566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, MATAIJ));
44150a96aa3bSJed Brown 
44169566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
441708401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse, PetscObjectComm((PetscObject)dmFine), PETSC_ERR_SUP, "Only interpolation from coarse DM for now");
44180a96aa3bSJed Brown 
44190a96aa3bSJed Brown   {
44200a96aa3bSJed Brown     DM        plexF, plexC;
44210a96aa3bSJed Brown     PetscSF   sf;
44220a96aa3bSJed Brown     PetscInt *cids;
44230a96aa3bSJed Brown     PetscInt  dofPerDim[4] = {1, 1, 1, 1};
44240a96aa3bSJed Brown 
44259566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse, &plexC));
44269566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine, &plexF));
44279566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
44289566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
44299566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
44309566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
44319566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
44320a96aa3bSJed Brown   }
44339566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
44340a96aa3bSJed Brown   /* Use naive scaling */
44359566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
44363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44370a96aa3bSJed Brown }
44380a96aa3bSJed Brown 
44390a96aa3bSJed Brown   #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
4440d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
4441d71ae5a4SJacob Faibussowitsch {
44420a96aa3bSJed Brown   PetscSection gsc, gsf;
44430a96aa3bSJed Brown   PetscInt     m, n;
44440a96aa3bSJed Brown   DM           cdm;
44450a96aa3bSJed Brown 
44460a96aa3bSJed Brown   PetscFunctionBegin;
44479566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
44489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n));
44499566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
44509566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m));
44510a96aa3bSJed Brown 
44529566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmFine), injection));
44539566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
44549566063dSJacob Faibussowitsch   PetscCall(MatSetType(*injection, MATAIJ));
44550a96aa3bSJed Brown 
44569566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
445708401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse, PetscObjectComm((PetscObject)dmFine), PETSC_ERR_SUP, "Only injection to coarse DM for now");
44580a96aa3bSJed Brown 
44590a96aa3bSJed Brown   {
44600a96aa3bSJed Brown     DM        plexF, plexC;
44610a96aa3bSJed Brown     PetscSF   sf;
44620a96aa3bSJed Brown     PetscInt *cids;
44630a96aa3bSJed Brown     PetscInt  dofPerDim[4] = {1, 1, 1, 1};
44640a96aa3bSJed Brown 
44659566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse, &plexC));
44669566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine, &plexF));
44679566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
44689566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
44699566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
44709566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
44719566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
44720a96aa3bSJed Brown   }
44739566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
44740a96aa3bSJed Brown   /* Use naive scaling */
44753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44760a96aa3bSJed Brown }
44770a96aa3bSJed Brown 
44780a96aa3bSJed Brown   #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
4479d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
4480d71ae5a4SJacob Faibussowitsch {
44810a96aa3bSJed Brown   DM        dmIn, dmVecIn, base, basec, plex, coarseDM;
44820a96aa3bSJed Brown   DM       *hierarchy;
44830a96aa3bSJed Brown   PetscSF   sfRed = NULL;
44840a96aa3bSJed Brown   PetscDS   ds;
44850a96aa3bSJed Brown   Vec       vecInLocal, vecOutLocal;
44860a96aa3bSJed Brown   DMLabel   subpointMap;
44870a96aa3bSJed Brown   PetscInt  minLevel, mh, n_hi, i;
44880a96aa3bSJed Brown   PetscBool hiforest, *hierarchy_forest;
44890a96aa3bSJed Brown 
44900a96aa3bSJed Brown   PetscFunctionBegin;
44919566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vecIn, &dmVecIn));
44929566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmVecIn, &ds));
449328b400f6SJacob Faibussowitsch   PetscCheck(ds, PetscObjectComm((PetscObject)dmVecIn), PETSC_ERR_SUP, "Cannot transfer without a PetscDS object");
44940a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
44950a96aa3bSJed Brown     PetscSection section;
44960a96aa3bSJed Brown     PetscInt     Nf;
44970a96aa3bSJed Brown 
44989566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn, &section));
44999566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
450063a3b9bcSJacob 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);
45010a96aa3bSJed Brown   }
45029566063dSJacob Faibussowitsch   PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
450363a3b9bcSJacob Faibussowitsch   PetscCheck(!minLevel, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)", minLevel);
45049566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
450528b400f6SJacob Faibussowitsch   PetscCheck(base, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing base DM");
45060a96aa3bSJed Brown 
45079566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
45080a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
45099566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45100a96aa3bSJed Brown   } else {
45110a96aa3bSJed Brown     PetscSection secIn, secInRed;
45120a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
45130a96aa3bSJed Brown 
45149566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)base, "_base_migration_sf", (PetscObject *)&sfRed));
451528b400f6SJacob Faibussowitsch     PetscCheck(sfRed, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not the DM set with DMForestSetBaseDM()");
45169566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn), &secInRed));
45179566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF, &vecInRed));
45189566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn, &secIn));
45199566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmVecIn, &vecInLocal));
45209566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmVecIn, vecIn, INSERT_VALUES, vecInLocal));
45219566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmVecIn, vecIn, INSERT_VALUES, vecInLocal));
45229566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeField(dmVecIn, sfRed, secIn, vecInLocal, secInRed, vecInRed));
45239566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmVecIn, &vecInLocal));
45249566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secInRed));
45250a96aa3bSJed Brown     vecIn = vecInRed;
45260a96aa3bSJed Brown   }
45270a96aa3bSJed Brown 
45280a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
45290a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
45300a96aa3bSJed Brown   hiforest = PETSC_TRUE;
45310a96aa3bSJed Brown 
45320a96aa3bSJed Brown   /* upsweep to the coarsest DM */
45330a96aa3bSJed Brown   n_hi     = 0;
45340a96aa3bSJed Brown   coarseDM = dm;
45350a96aa3bSJed Brown   do {
45360a96aa3bSJed Brown     PetscBool isforest;
45370a96aa3bSJed Brown 
45380a96aa3bSJed Brown     dmIn = coarseDM;
45390a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
45409566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dmIn));
45419566063dSJacob Faibussowitsch     PetscCall(DMIsForest(dmIn, &isforest));
454228b400f6SJacob Faibussowitsch     PetscCheck(isforest, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "Cannot currently transfer through a mixed hierarchy! Found DM type %s", ((PetscObject)dmIn)->type_name);
45430a96aa3bSJed Brown     coarseDM = NULL;
454448a46eb9SPierre Jolivet     if (hiforest) PetscCall(DMForestGetAdaptivityForest(dmIn, &coarseDM));
45450a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
45460a96aa3bSJed Brown       hiforest = PETSC_FALSE;
45479566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn, &coarseDM));
45480a96aa3bSJed Brown     }
45490a96aa3bSJed Brown     n_hi++;
45500a96aa3bSJed Brown   } while (coarseDM);
45510a96aa3bSJed Brown 
45529566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n_hi, &hierarchy, n_hi, &hierarchy_forest));
45530a96aa3bSJed Brown 
45540a96aa3bSJed Brown   i        = 0;
45550a96aa3bSJed Brown   hiforest = PETSC_TRUE;
45560a96aa3bSJed Brown   coarseDM = dm;
45570a96aa3bSJed Brown   do {
45580a96aa3bSJed Brown     dmIn     = coarseDM;
45590a96aa3bSJed Brown     coarseDM = NULL;
456048a46eb9SPierre Jolivet     if (hiforest) PetscCall(DMForestGetAdaptivityForest(dmIn, &coarseDM));
45610a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
45620a96aa3bSJed Brown       hiforest = PETSC_FALSE;
45639566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn, &coarseDM));
45640a96aa3bSJed Brown     }
45650a96aa3bSJed Brown     i++;
45660a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
45670a96aa3bSJed Brown   } while (coarseDM);
45680a96aa3bSJed Brown 
45690a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
45709566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn, &plex));
45710a96aa3bSJed Brown 
45720a96aa3bSJed Brown   /* Check this plex is compatible with the base */
45730a96aa3bSJed Brown   {
45740a96aa3bSJed Brown     IS       gnum[2];
45750a96aa3bSJed Brown     PetscInt ncells[2], gncells[2];
45760a96aa3bSJed Brown 
45779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(base, &gnum[0]));
45789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(plex, &gnum[1]));
45799566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[0], NULL, &ncells[0]));
45809566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[1], NULL, &ncells[1]));
45811c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(ncells, gncells, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
458263a3b9bcSJacob 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);
45830a96aa3bSJed Brown   }
45840a96aa3bSJed Brown 
45859566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dmIn, "_forest_base_subpoint_map", &subpointMap));
458628b400f6SJacob Faibussowitsch   PetscCheck(subpointMap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing _forest_base_subpoint_map label");
45870a96aa3bSJed Brown 
45889566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(base, &mh));
45899566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(plex, mh));
45900a96aa3bSJed Brown 
45919566063dSJacob Faibussowitsch   PetscCall(DMClone(base, &basec));
45929566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmVecIn, basec));
45930a96aa3bSJed Brown   if (sfRed) {
45949566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45950a96aa3bSJed Brown     vecInLocal = vecIn;
45960a96aa3bSJed Brown   } else {
45979566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(basec, &vecInLocal));
45989566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(basec, vecIn, INSERT_VALUES, vecInLocal));
45999566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(basec, vecIn, INSERT_VALUES, vecInLocal));
46000a96aa3bSJed Brown   }
46010a96aa3bSJed Brown 
46029566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmIn, &vecOutLocal));
46030a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
46040a96aa3bSJed Brown     PetscSF            basetocoarse;
46050a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
46060a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
46070a96aa3bSJed Brown     PetscMPIInt        rank;
46080a96aa3bSJed Brown     PetscSFNode       *remotes;
46090a96aa3bSJed Brown     PetscSection       secIn, secOut;
46100a96aa3bSJed Brown     PetscInt          *remoteOffsets;
46110a96aa3bSJed Brown     PetscSF            transferSF;
46120a96aa3bSJed Brown     const PetscScalar *inArray;
46130a96aa3bSJed Brown     PetscScalar       *outArray;
46140a96aa3bSJed Brown 
46159566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
46169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(basec, &bStart, &bEnd));
46170a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
46189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &iStart, &iEnd));
46190a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
46200a96aa3bSJed Brown 
46219566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &remotes));
46220a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
46230a96aa3bSJed Brown       PetscInt index;
46240a96aa3bSJed Brown 
46250a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
46269566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(subpointMap, leaf, &index));
46270a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
46280a96aa3bSJed Brown     }
46290a96aa3bSJed Brown 
46309566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
46319566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
46329566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(basetocoarse));
46339566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(basec, &secIn));
46349566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn), &secOut));
46359566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
46369566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
46379566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
46389566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(vecOutLocal, &outArray));
46399566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecInLocal, &inArray));
46409566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray, MPI_REPLACE));
46419566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray, MPI_REPLACE));
46429566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecInLocal, &inArray));
46439566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray));
46449566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferSF));
46459566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secOut));
46469566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&basetocoarse));
46470a96aa3bSJed Brown   }
46489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecInLocal));
46499566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&basec));
46509566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecIn));
46510a96aa3bSJed Brown 
46520a96aa3bSJed Brown   /* output */
46530a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
46540a96aa3bSJed Brown     Vec vecOut1, vecOut2;
46550a96aa3bSJed Brown     DM  fineDM;
46560a96aa3bSJed Brown 
46579566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmIn, &vecOut1));
46589566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn, vecOutLocal, INSERT_VALUES, vecOut1));
46599566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecOutLocal));
46600a96aa3bSJed Brown     for (i = 1; i < n_hi - 1; i++) {
46610a96aa3bSJed Brown       fineDM = hierarchy[i];
46629566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(fineDM, &vecOut2));
46639566063dSJacob Faibussowitsch       PetscCall(DMForestTransferVec(dmIn, vecOut1, fineDM, vecOut2, PETSC_TRUE, 0.0));
46649566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmIn, &vecOut1));
46650a96aa3bSJed Brown       vecOut1 = vecOut2;
46660a96aa3bSJed Brown       dmIn    = fineDM;
46670a96aa3bSJed Brown     }
46689566063dSJacob Faibussowitsch     PetscCall(DMForestTransferVec(dmIn, vecOut1, dm, vecOut, PETSC_TRUE, 0.0));
46699566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmIn, &vecOut1));
46700a96aa3bSJed Brown   } else {
46719566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn, vecOutLocal, INSERT_VALUES, vecOut));
46729566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecOutLocal));
46730a96aa3bSJed Brown   }
46749566063dSJacob Faibussowitsch   PetscCall(PetscFree2(hierarchy, hierarchy_forest));
46753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46760a96aa3bSJed Brown }
46770a96aa3bSJed Brown 
46780a96aa3bSJed Brown   #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
4679d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
4680d71ae5a4SJacob Faibussowitsch {
46810a96aa3bSJed Brown   DM          adaptIn, adaptOut, plexIn, plexOut;
46820a96aa3bSJed Brown   DM_Forest  *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
46830a96aa3bSJed Brown   PetscInt    dofPerDim[] = {1, 1, 1, 1};
46840a96aa3bSJed Brown   PetscSF     inSF = NULL, outSF = NULL;
46850a96aa3bSJed Brown   PetscInt   *inCids = NULL, *outCids = NULL;
46860a96aa3bSJed Brown   DMAdaptFlag purposeIn, purposeOut;
46870a96aa3bSJed Brown 
46880a96aa3bSJed Brown   PetscFunctionBegin;
46890a96aa3bSJed Brown   forestOut = (DM_Forest *)dmOut->data;
46900a96aa3bSJed Brown   forestIn  = (DM_Forest *)dmIn->data;
46910a96aa3bSJed Brown 
46929566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmOut, &adaptOut));
46939566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmOut, &purposeOut));
46940a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *)adaptOut->data : NULL;
46950a96aa3bSJed Brown 
46969566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmIn, &adaptIn));
46979566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmIn, &purposeIn));
46980a96aa3bSJed Brown   forestAdaptIn = adaptIn ? (DM_Forest *)adaptIn->data : NULL;
46990a96aa3bSJed Brown 
47000a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
47010a96aa3bSJed Brown     switch (purposeOut) {
47020a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47039566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47049566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47050a96aa3bSJed Brown       break;
47060a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
47070a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
47089566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_TRUE, &outCids));
47099566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47100a96aa3bSJed Brown       break;
47110a96aa3bSJed Brown     default:
47129566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47139566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_FALSE, &outCids));
47149566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47159566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47160a96aa3bSJed Brown     }
47170a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
47180a96aa3bSJed Brown     switch (purposeIn) {
47190a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47209566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_TRUE, &inCids));
47219566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47220a96aa3bSJed Brown       break;
47230a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
47240a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
47259566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47269566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47270a96aa3bSJed Brown       break;
47280a96aa3bSJed Brown     default:
47299566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47309566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_FALSE, &outCids));
47319566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47329566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47330a96aa3bSJed Brown     }
47340a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "Only support transfer from pre-adaptivity to post-adaptivity right now");
47359566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn, &plexIn));
47369566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmOut, &plexOut));
47370a96aa3bSJed Brown 
47389566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferVecTree(plexIn, vecIn, plexOut, vecOut, inSF, outSF, inCids, outCids, useBCs, time));
47399566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
47409566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
47419566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&inSF));
47429566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&outSF));
47439566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
47449566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
47453ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47460a96aa3bSJed Brown }
47470a96aa3bSJed Brown 
47480a96aa3bSJed Brown   #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
4749d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm, DM *cdm)
4750d71ae5a4SJacob Faibussowitsch {
47510a96aa3bSJed Brown   DM plex;
47520a96aa3bSJed Brown 
47530a96aa3bSJed Brown   PetscFunctionBegin;
47540a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47559566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(plex, cdm));
47579566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)*cdm));
47583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47590a96aa3bSJed Brown }
47600a96aa3bSJed Brown 
47610a96aa3bSJed Brown   #define VecViewLocal_pforest _append_pforest(VecViewLocal)
4762d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecViewLocal_pforest(Vec vec, PetscViewer viewer)
4763d71ae5a4SJacob Faibussowitsch {
47640a96aa3bSJed Brown   DM dm, plex;
47650a96aa3bSJed Brown 
47660a96aa3bSJed Brown   PetscFunctionBegin;
47679566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47689566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47699566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47709566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Local(vec, viewer));
47719566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
47723ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47730a96aa3bSJed Brown }
47740a96aa3bSJed Brown 
47750a96aa3bSJed Brown   #define VecView_pforest _append_pforest(VecView)
4776d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_pforest(Vec vec, PetscViewer viewer)
4777d71ae5a4SJacob Faibussowitsch {
47780a96aa3bSJed Brown   DM dm, plex;
47790a96aa3bSJed Brown 
47800a96aa3bSJed Brown   PetscFunctionBegin;
47819566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47829566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47839566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47849566063dSJacob Faibussowitsch   PetscCall(VecView_Plex(vec, viewer));
47859566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
47863ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47870a96aa3bSJed Brown }
47880a96aa3bSJed Brown 
47890a96aa3bSJed Brown   #define VecView_pforest_Native _infix_pforest(VecView, _Native)
4790d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_pforest_Native(Vec vec, PetscViewer viewer)
4791d71ae5a4SJacob Faibussowitsch {
47920a96aa3bSJed Brown   DM dm, plex;
47930a96aa3bSJed Brown 
47940a96aa3bSJed Brown   PetscFunctionBegin;
47959566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
47969566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47979566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47989566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Native(vec, viewer));
47999566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
48003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48010a96aa3bSJed Brown }
48020a96aa3bSJed Brown 
48030a96aa3bSJed Brown   #define VecLoad_pforest _append_pforest(VecLoad)
4804d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecLoad_pforest(Vec vec, PetscViewer viewer)
4805d71ae5a4SJacob Faibussowitsch {
48060a96aa3bSJed Brown   DM dm, plex;
48070a96aa3bSJed Brown 
48080a96aa3bSJed Brown   PetscFunctionBegin;
48099566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
48109566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48119566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
48129566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex(vec, viewer));
48139566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
48143ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48150a96aa3bSJed Brown }
48160a96aa3bSJed Brown 
48170a96aa3bSJed Brown   #define VecLoad_pforest_Native _infix_pforest(VecLoad, _Native)
4818d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecLoad_pforest_Native(Vec vec, PetscViewer viewer)
4819d71ae5a4SJacob Faibussowitsch {
48200a96aa3bSJed Brown   DM dm, plex;
48210a96aa3bSJed Brown 
48220a96aa3bSJed Brown   PetscFunctionBegin;
48239566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
48249566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48259566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
48269566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex_Native(vec, viewer));
48279566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
48283ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48290a96aa3bSJed Brown }
48300a96aa3bSJed Brown 
48310a96aa3bSJed Brown   #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
4832d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateGlobalVector_pforest(DM dm, Vec *vec)
4833d71ae5a4SJacob Faibussowitsch {
48340a96aa3bSJed Brown   PetscFunctionBegin;
48359566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
48369566063dSJacob Faibussowitsch   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
48379566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
48389566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
48399566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
48409566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
48413ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48420a96aa3bSJed Brown }
48430a96aa3bSJed Brown 
48440a96aa3bSJed Brown   #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
4845d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateLocalVector_pforest(DM dm, Vec *vec)
4846d71ae5a4SJacob Faibussowitsch {
48470a96aa3bSJed Brown   PetscFunctionBegin;
48489566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
48499566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
48503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48510a96aa3bSJed Brown }
48520a96aa3bSJed Brown 
48530a96aa3bSJed Brown   #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
4854d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_pforest(DM dm, Mat *mat)
4855d71ae5a4SJacob Faibussowitsch {
48560a96aa3bSJed Brown   DM plex;
48570a96aa3bSJed Brown 
48580a96aa3bSJed Brown   PetscFunctionBegin;
48590a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48609566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48610a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only; /* maybe this should go into forest->plex */
48629566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(plex, mat));
48639566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*mat, dm));
48643ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48650a96aa3bSJed Brown }
48660a96aa3bSJed Brown 
48670a96aa3bSJed Brown   #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
4868d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
4869d71ae5a4SJacob Faibussowitsch {
48700a96aa3bSJed Brown   DM plex;
48710a96aa3bSJed Brown 
48720a96aa3bSJed Brown   PetscFunctionBegin;
48730a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48749566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48759566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(plex, time, funcs, ctxs, mode, localX));
48763ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48770a96aa3bSJed Brown }
48780a96aa3bSJed Brown 
48790a96aa3bSJed Brown   #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
4880d71ae5a4SJacob 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)
4881d71ae5a4SJacob Faibussowitsch {
48820a96aa3bSJed Brown   DM plex;
48830a96aa3bSJed Brown 
48840a96aa3bSJed Brown   PetscFunctionBegin;
48850a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48869566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48879566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(plex, time, label, numIds, ids, Ncc, comps, funcs, ctxs, mode, localX));
48883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48890a96aa3bSJed Brown }
48900a96aa3bSJed Brown 
48910a96aa3bSJed Brown   #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
4892d71ae5a4SJacob 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)
4893d71ae5a4SJacob Faibussowitsch {
48940a96aa3bSJed Brown   DM plex;
48950a96aa3bSJed Brown 
48960a96aa3bSJed Brown   PetscFunctionBegin;
48970a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48989566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48999566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(plex, time, localU, funcs, mode, localX));
49003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49010a96aa3bSJed Brown }
49020a96aa3bSJed Brown 
49030a96aa3bSJed Brown   #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
4904d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
4905d71ae5a4SJacob Faibussowitsch {
49060a96aa3bSJed Brown   DM plex;
49070a96aa3bSJed Brown 
49080a96aa3bSJed Brown   PetscFunctionBegin;
49090a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49109566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49119566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(plex, time, funcs, ctxs, X, diff));
49123ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49130a96aa3bSJed Brown }
49140a96aa3bSJed Brown 
49150a96aa3bSJed Brown   #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
4916d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
4917d71ae5a4SJacob Faibussowitsch {
49180a96aa3bSJed Brown   DM plex;
49190a96aa3bSJed Brown 
49200a96aa3bSJed Brown   PetscFunctionBegin;
49210a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49229566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49239566063dSJacob Faibussowitsch   PetscCall(DMComputeL2FieldDiff(plex, time, funcs, ctxs, X, diff));
49243ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49250a96aa3bSJed Brown }
49260a96aa3bSJed Brown 
49270a96aa3bSJed Brown   #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
4928d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
4929d71ae5a4SJacob Faibussowitsch {
49300a96aa3bSJed Brown   DM           plex;
49310a96aa3bSJed Brown   PetscSection section;
49320a96aa3bSJed Brown 
49330a96aa3bSJed Brown   PetscFunctionBegin;
49340a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49359566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49369566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(plex, &section));
49379566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dm, section));
49383ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49390a96aa3bSJed Brown }
49400a96aa3bSJed Brown 
49410a96aa3bSJed Brown   #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
4942d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
4943d71ae5a4SJacob Faibussowitsch {
49440a96aa3bSJed Brown   DM           plex;
49450a96aa3bSJed Brown   Mat          mat;
494679769bd5SJed Brown   Vec          bias;
49470a96aa3bSJed Brown   PetscSection section;
49480a96aa3bSJed Brown 
49490a96aa3bSJed Brown   PetscFunctionBegin;
49500a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49519566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49529566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(plex, &section, &mat, &bias));
49539566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, section, mat, bias));
49543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49550a96aa3bSJed Brown }
49560a96aa3bSJed Brown 
49570a96aa3bSJed Brown   #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
4958d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
4959d71ae5a4SJacob Faibussowitsch {
49600a96aa3bSJed Brown   DM plex;
49610a96aa3bSJed Brown 
49620a96aa3bSJed Brown   PetscFunctionBegin;
49630a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49649566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49659566063dSJacob Faibussowitsch   PetscCall(DMGetDimPoints(plex, dim, cStart, cEnd));
49663ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49670a96aa3bSJed Brown }
49680a96aa3bSJed Brown 
49690a96aa3bSJed Brown   /* Need to forward declare */
49700a96aa3bSJed Brown   #define DMInitialize_pforest _append_pforest(DMInitialize)
49710a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
49720a96aa3bSJed Brown 
49730a96aa3bSJed Brown   #define DMClone_pforest _append_pforest(DMClone)
4974d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
4975d71ae5a4SJacob Faibussowitsch {
49760a96aa3bSJed Brown   PetscFunctionBegin;
49779566063dSJacob Faibussowitsch   PetscCall(DMClone_Forest(dm, newdm));
49789566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(*newdm));
49793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49800a96aa3bSJed Brown }
49810a96aa3bSJed Brown 
49820a96aa3bSJed Brown   #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
4983d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
4984d71ae5a4SJacob Faibussowitsch {
49850a96aa3bSJed Brown   DM_Forest         *forest;
49860a96aa3bSJed Brown   DM_Forest_pforest *pforest;
49870a96aa3bSJed Brown   PetscInt           overlap;
49880a96aa3bSJed Brown 
49890a96aa3bSJed Brown   PetscFunctionBegin;
49909566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
49910a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
49920a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
49930a96aa3bSJed Brown   *cStart = 0;
49949566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
49950a96aa3bSJed Brown   if (overlap && pforest->ghost) {
49960a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
49970a96aa3bSJed Brown   } else {
49980a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
49990a96aa3bSJed Brown   }
50003ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50010a96aa3bSJed Brown }
50020a96aa3bSJed Brown 
50030a96aa3bSJed Brown   #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
5004d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
5005d71ae5a4SJacob Faibussowitsch {
50060a96aa3bSJed Brown   DM_Forest         *forest;
50070a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50080a96aa3bSJed Brown   PetscMPIInt        rank;
50090a96aa3bSJed Brown   PetscInt           overlap;
50100a96aa3bSJed Brown   PetscInt           cStart, cEnd, cLocalStart, cLocalEnd;
50110a96aa3bSJed Brown   PetscInt           nRoots, nLeaves, *mine = NULL;
50120a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
50130a96aa3bSJed Brown   PetscSF            sf;
50140a96aa3bSJed Brown 
50150a96aa3bSJed Brown   PetscFunctionBegin;
50169566063dSJacob Faibussowitsch   PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
50170a96aa3bSJed Brown   forest      = (DM_Forest *)dm->data;
50180a96aa3bSJed Brown   pforest     = (DM_Forest_pforest *)forest->data;
50190a96aa3bSJed Brown   nRoots      = cEnd - cStart;
50200a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
50210a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
50220a96aa3bSJed Brown   nLeaves     = 0;
50239566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
50249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
50250a96aa3bSJed Brown   if (overlap && pforest->ghost) {
50260a96aa3bSJed Brown     PetscSFNode      *mirror;
50270a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
50280a96aa3bSJed Brown     PetscInt          nMirror, nGhostPre, nSelf, q;
50290a96aa3bSJed Brown     void            **mirrorPtrs;
50300a96aa3bSJed Brown 
50310a96aa3bSJed Brown     nMirror   = (PetscInt)pforest->ghost->mirrors.elem_count;
50320a96aa3bSJed Brown     nSelf     = cLocalEnd - cLocalStart;
50330a96aa3bSJed Brown     nLeaves   = nRoots - nSelf;
50340a96aa3bSJed Brown     nGhostPre = (PetscInt)pforest->ghost->proc_offsets[rank];
50359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &mine));
50369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &remote));
50379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nMirror, &mirror, nMirror, &mirrorPtrs));
50380a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t *)pforest->ghost->mirrors.array;
50390a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
50400a96aa3bSJed Brown       p4est_quadrant_t *mir = &(mirror_array[q]);
50410a96aa3bSJed Brown 
50420a96aa3bSJed Brown       mirror[q].rank  = rank;
50430a96aa3bSJed Brown       mirror[q].index = (PetscInt)mir->p.piggy3.local_num + cLocalStart;
50440a96aa3bSJed Brown       mirrorPtrs[q]   = (void *)&(mirror[q]);
50450a96aa3bSJed Brown     }
5046792fecdfSBarry Smith     PetscCallP4est(p4est_ghost_exchange_custom, (pforest->forest, pforest->ghost, sizeof(PetscSFNode), mirrorPtrs, remote));
50479566063dSJacob Faibussowitsch     PetscCall(PetscFree2(mirror, mirrorPtrs));
50480a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
50490a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
50500a96aa3bSJed Brown   }
50519566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &sf));
50529566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nRoots, nLeaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
50530a96aa3bSJed Brown   *cellSF = sf;
50543ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50550a96aa3bSJed Brown }
50560a96aa3bSJed Brown 
5057d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS *ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void *), void **setup_ctx)
5058d71ae5a4SJacob Faibussowitsch {
50590a96aa3bSJed Brown   DM plex;
50600a96aa3bSJed Brown 
50610a96aa3bSJed Brown   PetscFunctionBegin;
50629566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
50639566063dSJacob Faibussowitsch   PetscCall(DMCreateNeumannOverlap_Plex(plex, ovl, J, setup, setup_ctx));
50640a96aa3bSJed Brown   if (!*setup) {
50659566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
506648a46eb9SPierre Jolivet     if (*setup) PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
50670a96aa3bSJed Brown   }
50683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50690a96aa3bSJed Brown }
50700a96aa3bSJed Brown 
5071*907a3e9cSStefano Zampini   #define DMCreateDomainDecomposition_pforest _append_pforest(DMCreateDomainDecomposition)
5072*907a3e9cSStefano Zampini static PetscErrorCode DMCreateDomainDecomposition_pforest(DM dm, PetscInt *nsub, char ***names, IS **innerises, IS **outerises, DM **dms)
5073*907a3e9cSStefano Zampini {
5074*907a3e9cSStefano Zampini   DM plex;
5075*907a3e9cSStefano Zampini 
5076*907a3e9cSStefano Zampini   PetscFunctionBegin;
5077*907a3e9cSStefano Zampini   PetscCall(DMPforestGetPlex(dm, &plex));
5078*907a3e9cSStefano Zampini   PetscCall(DMCreateDomainDecomposition(plex, nsub, names, innerises, outerises, dms));
5079*907a3e9cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
5080*907a3e9cSStefano Zampini }
5081*907a3e9cSStefano Zampini 
5082*907a3e9cSStefano Zampini   #define DMCreateDomainDecompositionScatters_pforest _append_pforest(DMCreateDomainDecompositionScatters)
5083*907a3e9cSStefano Zampini static PetscErrorCode DMCreateDomainDecompositionScatters_pforest(DM dm, PetscInt n, DM *subdms, VecScatter **iscat, VecScatter **oscat, VecScatter **lscat)
5084*907a3e9cSStefano Zampini {
5085*907a3e9cSStefano Zampini   DM plex;
5086*907a3e9cSStefano Zampini 
5087*907a3e9cSStefano Zampini   PetscFunctionBegin;
5088*907a3e9cSStefano Zampini   PetscCall(DMPforestGetPlex(dm, &plex));
5089*907a3e9cSStefano Zampini   PetscCall(DMCreateDomainDecompositionScatters(plex, n, subdms, iscat, oscat, lscat));
5090*907a3e9cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
5091*907a3e9cSStefano Zampini }
5092*907a3e9cSStefano Zampini 
5093d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_pforest(DM dm)
5094d71ae5a4SJacob Faibussowitsch {
50950a96aa3bSJed Brown   PetscFunctionBegin;
50960a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
50970a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
50980a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
50990a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
51000a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
51010a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
51020a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
51030a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
51040a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
51050a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
51060a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
51070a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
51080a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
51090a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
51100a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
51110a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
51120a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
51130a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
5114*907a3e9cSStefano Zampini   dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_pforest;
5115*907a3e9cSStefano Zampini   dm->ops->createddscatters          = DMCreateDomainDecompositionScatters_pforest;
51160a96aa3bSJed Brown 
51179566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_plex_pforest) "_C", DMConvert_plex_pforest));
51189566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_pforest_plex) "_C", DMConvert_pforest_plex));
51199566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_pforest));
51209566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMForestGetPartitionOverlap));
51213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51220a96aa3bSJed Brown }
51230a96aa3bSJed Brown 
51240a96aa3bSJed Brown   #define DMCreate_pforest _append_pforest(DMCreate)
5125d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
5126d71ae5a4SJacob Faibussowitsch {
51270a96aa3bSJed Brown   DM_Forest         *forest;
51280a96aa3bSJed Brown   DM_Forest_pforest *pforest;
51290a96aa3bSJed Brown 
51300a96aa3bSJed Brown   PetscFunctionBegin;
51319566063dSJacob Faibussowitsch   PetscCall(PetscP4estInitialize());
51329566063dSJacob Faibussowitsch   PetscCall(DMCreate_Forest(dm));
51339566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(dm));
51349566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, P4EST_DIM));
51350a96aa3bSJed Brown 
51360a96aa3bSJed Brown   /* set forest defaults */
51379566063dSJacob Faibussowitsch   PetscCall(DMForestSetTopology(dm, "unit"));
51389566063dSJacob Faibussowitsch   PetscCall(DMForestSetMinimumRefinement(dm, 0));
51399566063dSJacob Faibussowitsch   PetscCall(DMForestSetInitialRefinement(dm, 0));
51409566063dSJacob Faibussowitsch   PetscCall(DMForestSetMaximumRefinement(dm, P4EST_QMAXLEVEL));
51419566063dSJacob Faibussowitsch   PetscCall(DMForestSetGradeFactor(dm, 2));
51429566063dSJacob Faibussowitsch   PetscCall(DMForestSetAdjacencyDimension(dm, 0));
51439566063dSJacob Faibussowitsch   PetscCall(DMForestSetPartitionOverlap(dm, 0));
51440a96aa3bSJed Brown 
51450a96aa3bSJed Brown   /* create p4est data */
51464dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pforest));
51470a96aa3bSJed Brown 
51480a96aa3bSJed Brown   forest                            = (DM_Forest *)dm->data;
51490a96aa3bSJed Brown   forest->data                      = pforest;
51500a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
51510a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
51520a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
51530a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
51540a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
51550a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
51560a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
51570a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
51580a96aa3bSJed Brown   pforest->topo                     = NULL;
51590a96aa3bSJed Brown   pforest->forest                   = NULL;
51600a96aa3bSJed Brown   pforest->ghost                    = NULL;
51610a96aa3bSJed Brown   pforest->lnodes                   = NULL;
51620a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
51630a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
51640a96aa3bSJed Brown   pforest->cLocalStart              = -1;
51650a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
51660a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
51670a96aa3bSJed Brown   pforest->ghostName                = NULL;
51683ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51690a96aa3bSJed Brown }
51700a96aa3bSJed Brown 
51710a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5172