xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision f4f49eeac7efa77fffa46b7ff95a3ed169f659ed)
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   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
3660a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
3679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPLEX, &isPlex));
36828b400f6SJacob Faibussowitsch   PetscCheck(isPlex, comm, PETSC_ERR_ARG_WRONG, "Expected DM type %s, got %s", DMPLEX, ((PetscObject)dm)->type_name);
3699566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
37063a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Expected DM dimension %d, got %" PetscInt_FMT, P4EST_DIM, dim);
3719566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm, pforest));
3729566063dSJacob Faibussowitsch   PetscCall(DMSetType(*pforest, DMPFOREST));
3739566063dSJacob Faibussowitsch   PetscCall(DMForestSetBaseDM(*pforest, dm));
3749566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dm, &ctx));
3759566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(*pforest, ctx));
3769566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm, *pforest));
3773ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3780a96aa3bSJed Brown }
3790a96aa3bSJed Brown 
3800a96aa3bSJed Brown   #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
381d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestDestroy_pforest(DM dm)
382d71ae5a4SJacob Faibussowitsch {
3830a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
3840a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
3850a96aa3bSJed Brown 
3860a96aa3bSJed Brown   PetscFunctionBegin;
3870a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
388792fecdfSBarry Smith   if (pforest->lnodes) PetscCallP4est(p4est_lnodes_destroy, (pforest->lnodes));
3890a96aa3bSJed Brown   pforest->lnodes = NULL;
390792fecdfSBarry Smith   if (pforest->ghost) PetscCallP4est(p4est_ghost_destroy, (pforest->ghost));
3910a96aa3bSJed Brown   pforest->ghost = NULL;
392792fecdfSBarry Smith   if (pforest->forest) PetscCallP4est(p4est_destroy, (pforest->forest));
3930a96aa3bSJed Brown   pforest->forest = NULL;
3949566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&pforest->topo));
3959566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->ghostName));
3969566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&pforest->plex));
3979566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
3989566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
3999566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
4009566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
4019566063dSJacob Faibussowitsch   PetscCall(PetscFree(forest->data));
4023ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4030a96aa3bSJed Brown }
4040a96aa3bSJed Brown 
4050a96aa3bSJed Brown   #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
406d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm)
407d71ae5a4SJacob Faibussowitsch {
4080a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
4090a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest *)((DM_Forest *)tdm->data)->data;
4100a96aa3bSJed Brown 
4110a96aa3bSJed Brown   PetscFunctionBegin;
4120a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
413*f4f49eeaSPierre Jolivet   PetscCall(DMFTopologyDestroy_pforest(&tpforest->topo));
4140a96aa3bSJed Brown   tpforest->topo = pforest->topo;
4153ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
4160a96aa3bSJed Brown }
4170a96aa3bSJed Brown 
4180a96aa3bSJed Brown   #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
4190a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM, p4est_connectivity_t **, PetscInt **);
4200a96aa3bSJed Brown 
4219371c9d4SSatish Balay typedef struct _PforestAdaptCtx {
4220a96aa3bSJed Brown   PetscInt  maxLevel;
4230a96aa3bSJed Brown   PetscInt  minLevel;
4240a96aa3bSJed Brown   PetscInt  currLevel;
4250a96aa3bSJed Brown   PetscBool anyChange;
4269371c9d4SSatish Balay } PforestAdaptCtx;
4270a96aa3bSJed Brown 
428d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_currlevel(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
429d71ae5a4SJacob Faibussowitsch {
4300a96aa3bSJed Brown   PforestAdaptCtx *ctx       = (PforestAdaptCtx *)p4est->user_pointer;
4310a96aa3bSJed Brown   PetscInt         minLevel  = ctx->minLevel;
4320a96aa3bSJed Brown   PetscInt         currLevel = ctx->currLevel;
4330a96aa3bSJed Brown 
4340a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4350a96aa3bSJed Brown   return (int)((PetscInt)quadrants[0]->level == currLevel);
4360a96aa3bSJed Brown }
4370a96aa3bSJed Brown 
438d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_uniform(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
439d71ae5a4SJacob Faibussowitsch {
4400a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4410a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4420a96aa3bSJed Brown 
4430a96aa3bSJed Brown   return (int)((PetscInt)quadrants[0]->level > minLevel);
4440a96aa3bSJed Brown }
4450a96aa3bSJed Brown 
446d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_flag_any(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
447d71ae5a4SJacob Faibussowitsch {
4480a96aa3bSJed Brown   PetscInt         i;
4490a96aa3bSJed Brown   PetscBool        any      = PETSC_FALSE;
4500a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4510a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4520a96aa3bSJed Brown 
4530a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4540a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4550a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
4560a96aa3bSJed Brown       any = PETSC_FALSE;
4570a96aa3bSJed Brown       break;
4580a96aa3bSJed Brown     }
4590a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
4600a96aa3bSJed Brown       any = PETSC_TRUE;
4610a96aa3bSJed Brown       break;
4620a96aa3bSJed Brown     }
4630a96aa3bSJed Brown   }
4640a96aa3bSJed Brown   return any ? 1 : 0;
4650a96aa3bSJed Brown }
4660a96aa3bSJed Brown 
467d71ae5a4SJacob Faibussowitsch static int pforest_coarsen_flag_all(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
468d71ae5a4SJacob Faibussowitsch {
4690a96aa3bSJed Brown   PetscInt         i;
4700a96aa3bSJed Brown   PetscBool        all      = PETSC_TRUE;
4710a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4720a96aa3bSJed Brown   PetscInt         minLevel = ctx->minLevel;
4730a96aa3bSJed Brown 
4740a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4750a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4760a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
4770a96aa3bSJed Brown       all = PETSC_FALSE;
4780a96aa3bSJed Brown       break;
4790a96aa3bSJed Brown     }
4800a96aa3bSJed Brown   }
4810a96aa3bSJed Brown   return all ? 1 : 0;
4820a96aa3bSJed Brown }
4830a96aa3bSJed Brown 
484d71ae5a4SJacob Faibussowitsch static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
485d71ae5a4SJacob Faibussowitsch {
4860a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
4870a96aa3bSJed Brown }
4880a96aa3bSJed Brown 
489d71ae5a4SJacob Faibussowitsch static int pforest_refine_uniform(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
490d71ae5a4SJacob Faibussowitsch {
4910a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
4920a96aa3bSJed Brown   PetscInt         maxLevel = ctx->maxLevel;
4930a96aa3bSJed Brown 
4940a96aa3bSJed Brown   return ((PetscInt)quadrant->level < maxLevel);
4950a96aa3bSJed Brown }
4960a96aa3bSJed Brown 
497d71ae5a4SJacob Faibussowitsch static int pforest_refine_flag(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
498d71ae5a4SJacob Faibussowitsch {
4990a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx *)p4est->user_pointer;
5000a96aa3bSJed Brown   PetscInt         maxLevel = ctx->maxLevel;
5010a96aa3bSJed Brown 
5020a96aa3bSJed Brown   if ((PetscInt)quadrant->level >= maxLevel) return 0;
5030a96aa3bSJed Brown 
5040a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
5050a96aa3bSJed Brown }
5060a96aa3bSJed Brown 
507d71ae5a4SJacob 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)
508d71ae5a4SJacob Faibussowitsch {
5090a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
5100a96aa3bSJed Brown   p4est_topidx_t t;
5110a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
5120a96aa3bSJed Brown 
5130a96aa3bSJed Brown   PetscFunctionBegin;
5145a96e07bSStefano Zampini   /* -Wmaybe-uninitialized */
5155a96e07bSStefano Zampini   *toFineLeavesCount   = 0;
5165a96e07bSStefano Zampini   *fromFineLeavesCount = 0;
5170a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
5180a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t *)p4estFrom->trees->array)[t]);
5190a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t *)p4estTo->trees->array)[t]);
5200a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
5210a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
5220a96aa3bSJed Brown     PetscInt          numFrom   = (PetscInt)treeFrom->quadrants.elem_count;
5230a96aa3bSJed Brown     PetscInt          numTo     = (PetscInt)treeTo->quadrants.elem_count;
5240a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t *)treeFrom->quadrants.array;
5250a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t *)treeTo->quadrants.array;
5260a96aa3bSJed Brown     PetscInt          currentFrom, currentTo;
5270a96aa3bSJed Brown     PetscInt          treeOffsetFrom = (PetscInt)treeFrom->quadrants_offset;
5280a96aa3bSJed Brown     PetscInt          treeOffsetTo   = (PetscInt)treeTo->quadrants_offset;
5290a96aa3bSJed Brown     int               comp;
5300a96aa3bSJed Brown 
531792fecdfSBarry Smith     PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (firstFrom, firstTo));
53228b400f6SJacob Faibussowitsch     PetscCheck(comp, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "non-matching partitions");
5330a96aa3bSJed Brown 
5340a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
5350a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
5360a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
5370a96aa3bSJed Brown 
5380a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
5390a96aa3bSJed Brown         if (toLeaves) {
5400a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5410a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
5420a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5430a96aa3bSJed Brown         }
5440a96aa3bSJed Brown         toFineLeaves++;
5450a96aa3bSJed Brown         currentFrom++;
5460a96aa3bSJed Brown         currentTo++;
5470a96aa3bSJed Brown       } else {
5480a96aa3bSJed Brown         int fromIsAncestor;
5490a96aa3bSJed Brown 
550792fecdfSBarry Smith         PetscCallP4estReturn(fromIsAncestor, p4est_quadrant_is_ancestor, (quadFrom, quadTo));
5510a96aa3bSJed Brown         if (fromIsAncestor) {
5520a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5530a96aa3bSJed Brown 
5540a96aa3bSJed Brown           if (toLeaves) {
5550a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5560a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
5570a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5580a96aa3bSJed Brown           }
5590a96aa3bSJed Brown           toFineLeaves++;
5600a96aa3bSJed Brown           currentTo++;
561792fecdfSBarry Smith           PetscCallP4est(p4est_quadrant_last_descendant, (quadFrom, &lastDesc, quadTo->level));
562792fecdfSBarry Smith           PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (quadTo, &lastDesc));
5630a96aa3bSJed Brown           if (comp) currentFrom++;
5640a96aa3bSJed Brown         } else {
5650a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5660a96aa3bSJed Brown 
5670a96aa3bSJed Brown           if (fromLeaves) {
5680a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
5690a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
5700a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
5710a96aa3bSJed Brown           }
5720a96aa3bSJed Brown           fromFineLeaves++;
5730a96aa3bSJed Brown           currentFrom++;
574792fecdfSBarry Smith           PetscCallP4est(p4est_quadrant_last_descendant, (quadTo, &lastDesc, quadFrom->level));
575792fecdfSBarry Smith           PetscCallP4estReturn(comp, p4est_quadrant_is_equal, (quadFrom, &lastDesc));
5760a96aa3bSJed Brown           if (comp) currentTo++;
5770a96aa3bSJed Brown         }
5780a96aa3bSJed Brown       }
5790a96aa3bSJed Brown     }
5800a96aa3bSJed Brown   }
5810a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
5820a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
5833ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
5840a96aa3bSJed Brown }
5850a96aa3bSJed Brown 
5860a96aa3bSJed Brown /* Compute the maximum level across all the trees */
587d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev)
588d71ae5a4SJacob Faibussowitsch {
5890a96aa3bSJed Brown   p4est_topidx_t     t, flt, llt;
5900a96aa3bSJed Brown   DM_Forest         *forest      = (DM_Forest *)dm->data;
5910a96aa3bSJed Brown   DM_Forest_pforest *pforest     = (DM_Forest_pforest *)forest->data;
5920a96aa3bSJed Brown   PetscInt           maxlevelloc = 0;
5930a96aa3bSJed Brown   p4est_t           *p4est;
5940a96aa3bSJed Brown 
5950a96aa3bSJed Brown   PetscFunctionBegin;
59628b400f6SJacob Faibussowitsch   PetscCheck(pforest, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing DM_Forest_pforest");
59728b400f6SJacob Faibussowitsch   PetscCheck(pforest->forest, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Missing p4est_t");
5980a96aa3bSJed Brown   p4est = pforest->forest;
5990a96aa3bSJed Brown   flt   = p4est->first_local_tree;
6000a96aa3bSJed Brown   llt   = p4est->last_local_tree;
6010a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
6020a96aa3bSJed Brown     p4est_tree_t *tree = &(((p4est_tree_t *)p4est->trees->array)[t]);
6030a96aa3bSJed Brown     maxlevelloc        = PetscMax((PetscInt)tree->maxlevel, maxlevelloc);
6040a96aa3bSJed Brown   }
6051c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&maxlevelloc, lev, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
6063ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6070a96aa3bSJed Brown }
6080a96aa3bSJed Brown 
6090a96aa3bSJed Brown /* Puts identity in coarseToFine */
6100a96aa3bSJed Brown /* assumes a matching partition */
611d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine)
612d71ae5a4SJacob Faibussowitsch {
6130a96aa3bSJed Brown   p4est_topidx_t flt, llt;
6140a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
6150a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
6160a96aa3bSJed Brown   PetscInt      *fromLeaves = NULL, *toLeaves = NULL;
6170a96aa3bSJed Brown   PetscSFNode   *fromRoots = NULL, *toRoots = NULL;
6180a96aa3bSJed Brown 
6190a96aa3bSJed Brown   PetscFunctionBegin;
6200a96aa3bSJed Brown   flt = p4estFrom->first_local_tree;
6210a96aa3bSJed Brown   llt = p4estFrom->last_local_tree;
6229566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &fromCoarse));
62348a46eb9SPierre Jolivet   if (toCoarseFromFine) PetscCall(PetscSFCreate(comm, &toCoarse));
6240a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
6250a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
6269566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom, FromOffset, p4estTo, ToOffset, flt, llt, &numLeavesTo, NULL, NULL, &numLeavesFrom, NULL, NULL));
6279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo, &toLeaves));
6289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo, &fromRoots));
6290a96aa3bSJed Brown   if (toCoarseFromFine) {
6309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom, &fromLeaves));
6319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom, &fromRoots));
6320a96aa3bSJed Brown   }
6339566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom, FromOffset, p4estTo, ToOffset, flt, llt, &numLeavesTo, toLeaves, fromRoots, &numLeavesFrom, fromLeaves, toRoots));
6340a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
6359566063dSJacob Faibussowitsch     PetscCall(PetscFree(toLeaves));
6369566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(fromCoarse, numRootsFrom, numLeavesTo, NULL, PETSC_OWN_POINTER, fromRoots, PETSC_OWN_POINTER));
6371baa6e33SBarry Smith   } else PetscCall(PetscSFSetGraph(fromCoarse, numRootsFrom, numLeavesTo, toLeaves, PETSC_OWN_POINTER, fromRoots, PETSC_OWN_POINTER));
6380a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
6390a96aa3bSJed Brown   if (toCoarseFromFine) {
6409566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(toCoarse, numRootsTo, numLeavesFrom, fromLeaves, PETSC_OWN_POINTER, toRoots, PETSC_OWN_POINTER));
6410a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
6420a96aa3bSJed Brown   }
6433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6440a96aa3bSJed Brown }
6450a96aa3bSJed Brown 
6460a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
647d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB)
648d71ae5a4SJacob Faibussowitsch {
649*f4f49eeaSPierre Jolivet   p4est_quadrant_t *myCoarseStart = &p4estA->global_first_position[rank];
650*f4f49eeaSPierre Jolivet   p4est_quadrant_t *myCoarseEnd   = &p4estA->global_first_position[rank + 1];
6510a96aa3bSJed Brown   p4est_quadrant_t *globalFirstB  = p4estB->global_first_position;
6520a96aa3bSJed Brown 
6530a96aa3bSJed Brown   PetscFunctionBegin;
6540a96aa3bSJed Brown   *startB = -1;
6550a96aa3bSJed Brown   *endB   = -1;
6560a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
6570a96aa3bSJed Brown     PetscInt lo, hi, guess;
6580a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
6590a96aa3bSJed Brown     lo    = 0;
6600a96aa3bSJed Brown     hi    = size;
6610a96aa3bSJed Brown     guess = rank;
6620a96aa3bSJed Brown     while (1) {
6630a96aa3bSJed Brown       int startCompMy, myCompEnd;
6640a96aa3bSJed Brown 
665792fecdfSBarry Smith       PetscCallP4estReturn(startCompMy, p4est_quadrant_compare_piggy, (&globalFirstB[guess], myCoarseStart));
666792fecdfSBarry Smith       PetscCallP4estReturn(myCompEnd, p4est_quadrant_compare_piggy, (myCoarseStart, &globalFirstB[guess + 1]));
6670a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
6680a96aa3bSJed Brown         *startB = guess;
6690a96aa3bSJed Brown         break;
6700a96aa3bSJed Brown       } else if (startCompMy > 0) { /* guess is to high */
6710a96aa3bSJed Brown         hi = guess;
6720a96aa3bSJed Brown       } else { /* guess is to low */
6730a96aa3bSJed Brown         lo = guess + 1;
6740a96aa3bSJed Brown       }
6750a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6760a96aa3bSJed Brown     }
6770a96aa3bSJed Brown     /* reset bounds, but not guess */
6780a96aa3bSJed Brown     lo = 0;
6790a96aa3bSJed Brown     hi = size;
6800a96aa3bSJed Brown     while (1) {
6810a96aa3bSJed Brown       int startCompMy, myCompEnd;
6820a96aa3bSJed Brown 
683792fecdfSBarry Smith       PetscCallP4estReturn(startCompMy, p4est_quadrant_compare_piggy, (&globalFirstB[guess], myCoarseEnd));
684792fecdfSBarry Smith       PetscCallP4estReturn(myCompEnd, p4est_quadrant_compare_piggy, (myCoarseEnd, &globalFirstB[guess + 1]));
6850a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
6860a96aa3bSJed Brown         *endB = guess + 1;
6870a96aa3bSJed Brown         break;
6880a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
6890a96aa3bSJed Brown         hi = guess;
6900a96aa3bSJed Brown       } else { /* guess is to low */
6910a96aa3bSJed Brown         lo = guess + 1;
6920a96aa3bSJed Brown       }
6930a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6940a96aa3bSJed Brown     }
6950a96aa3bSJed Brown   }
6963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
6970a96aa3bSJed Brown }
6980a96aa3bSJed Brown 
6990a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM, DM *);
7000a96aa3bSJed Brown 
7010a96aa3bSJed Brown   #define DMSetUp_pforest _append_pforest(DMSetUp)
702d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSetUp_pforest(DM dm)
703d71ae5a4SJacob Faibussowitsch {
7040a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
7050a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
7060a96aa3bSJed Brown   DM                 base, adaptFrom;
7070a96aa3bSJed Brown   DMForestTopology   topoName;
7080a96aa3bSJed Brown   PetscSF            preCoarseToFine = NULL, coarseToPreFine = NULL;
7090a96aa3bSJed Brown   PforestAdaptCtx    ctx;
7100a96aa3bSJed Brown 
7110a96aa3bSJed Brown   PetscFunctionBegin;
7120a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
7130a96aa3bSJed Brown   ctx.maxLevel  = 0;
7140a96aa3bSJed Brown   ctx.currLevel = 0;
7150a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
7160a96aa3bSJed Brown   /* sanity check */
7179566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm, &adaptFrom));
7189566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
7199566063dSJacob Faibussowitsch   PetscCall(DMForestGetTopology(dm, &topoName));
7201dca8a05SBarry 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");
7210a96aa3bSJed Brown 
7220a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
7230a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
7240a96aa3bSJed Brown     PetscBool          ispforest;
7250a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest *)adaptFrom->data;
7260a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest *)aforest->data;
7270a96aa3bSJed Brown 
7289566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)adaptFrom, DMPFOREST, &ispforest));
72928b400f6SJacob Faibussowitsch     PetscCheck(ispforest, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_NOTSAMETYPE, "Trying to adapt from %s, which is not %s", ((PetscObject)adaptFrom)->type_name, DMPFOREST);
73028b400f6SJacob Faibussowitsch     PetscCheck(apforest->topo, PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONGSTATE, "The pre-adaptation forest must have a topology");
7319566063dSJacob Faibussowitsch     PetscCall(DMSetUp(adaptFrom));
7329566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm, &base));
7339566063dSJacob Faibussowitsch     PetscCall(DMForestGetTopology(dm, &topoName));
7340a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
7350a96aa3bSJed Brown     PetscBool isPlex, isDA;
7360a96aa3bSJed Brown 
7379566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)base, &topoName));
7389566063dSJacob Faibussowitsch     PetscCall(DMForestSetTopology(dm, topoName));
7399566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base, DMPLEX, &isPlex));
7409566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base, DMDA, &isDA));
7410a96aa3bSJed Brown     if (isPlex) {
7420a96aa3bSJed Brown       MPI_Comm              comm = PetscObjectComm((PetscObject)dm);
7430a96aa3bSJed Brown       PetscInt              depth;
7440a96aa3bSJed Brown       PetscMPIInt           size;
7450a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
7460a96aa3bSJed Brown       DMFTopology_pforest  *topo;
7470a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
7480a96aa3bSJed Brown 
7499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepth(base, &depth));
7500a96aa3bSJed Brown       if (depth == 1) {
7510a96aa3bSJed Brown         DM connDM;
7520a96aa3bSJed Brown 
7539566063dSJacob Faibussowitsch         PetscCall(DMPlexInterpolate(base, &connDM));
7540a96aa3bSJed Brown         base = connDM;
7559566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm, base));
7569566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&connDM));
75763a3b9bcSJacob 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);
7589566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(comm, &size));
7590a96aa3bSJed Brown       if (size > 1) {
7600a96aa3bSJed Brown         DM      dmRedundant;
7610a96aa3bSJed Brown         PetscSF sf;
7620a96aa3bSJed Brown 
7639566063dSJacob Faibussowitsch         PetscCall(DMPlexGetRedundantDM(base, &sf, &dmRedundant));
76428b400f6SJacob Faibussowitsch         PetscCheck(dmRedundant, comm, PETSC_ERR_PLIB, "Could not create redundant DM");
7659566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)dmRedundant, "_base_migration_sf", (PetscObject)sf));
7669566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&sf));
7670a96aa3bSJed Brown         base = dmRedundant;
7689566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm, base));
7699566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&dmRedundant));
7700a96aa3bSJed Brown       }
7719566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(base, NULL, "-dm_p4est_base_view"));
7729566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateConnectivity_pforest(base, &conn, &tree_face_to_uniq));
7734dfa11a4SJacob Faibussowitsch       PetscCall(PetscNew(&topo));
7740a96aa3bSJed Brown       topo->refct = 1;
7750a96aa3bSJed Brown       topo->conn  = conn;
7760a96aa3bSJed Brown       topo->geom  = NULL;
7770a96aa3bSJed Brown       {
7780a96aa3bSJed Brown         PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
7790a96aa3bSJed Brown         void *mapCtx;
7800a96aa3bSJed Brown 
7819566063dSJacob Faibussowitsch         PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
7820a96aa3bSJed Brown         if (map) {
7830a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
7840a96aa3bSJed Brown           p4est_geometry_t           *geom;
7850a96aa3bSJed Brown 
7869566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom_pforest));
7879566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinateDim(dm, &geom_pforest->coordDim));
7880a96aa3bSJed Brown           geom_pforest->map    = map;
7890a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
790792fecdfSBarry Smith           PetscCallP4estReturn(geom_pforest->inner, p4est_geometry_new_connectivity, (conn));
7919566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom));
7920a96aa3bSJed Brown           geom->name    = topoName;
7930a96aa3bSJed Brown           geom->user    = geom_pforest;
7940a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
7950a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
7960a96aa3bSJed Brown           topo->geom    = geom;
7970a96aa3bSJed Brown         }
7980a96aa3bSJed Brown       }
7990a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
8000a96aa3bSJed Brown       pforest->topo           = topo;
80128b400f6SJacob Faibussowitsch     } else PetscCheck(!isDA, PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Not implemented yet");
8020a96aa3bSJed Brown   #if 0
8030a96aa3bSJed Brown       PetscInt N[3], P[3];
8040a96aa3bSJed Brown 
8050a96aa3bSJed Brown       /* get the sizes, periodicities */
8060a96aa3bSJed Brown       /* ... */
8070a96aa3bSJed Brown                                                                   /* don't use Morton order */
8089566063dSJacob Faibussowitsch       PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE));
8090a96aa3bSJed Brown   #endif
8100a96aa3bSJed Brown     {
8110a96aa3bSJed Brown       PetscInt numLabels, l;
8120a96aa3bSJed Brown 
8139566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(base, &numLabels));
8140a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
8150a96aa3bSJed Brown         PetscBool   isDepth, isGhost, isVTK, isDim, isCellType;
8160a96aa3bSJed Brown         DMLabel     label, labelNew;
8170a96aa3bSJed Brown         PetscInt    defVal;
8180a96aa3bSJed Brown         const char *name;
8190a96aa3bSJed Brown 
8209566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(base, l, &name));
8219566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(base, l, &label));
8229566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "depth", &isDepth));
8230a96aa3bSJed Brown         if (isDepth) continue;
8249566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "dim", &isDim));
8250a96aa3bSJed Brown         if (isDim) continue;
8269566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "celltype", &isCellType));
8270a96aa3bSJed Brown         if (isCellType) continue;
8289566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "ghost", &isGhost));
8290a96aa3bSJed Brown         if (isGhost) continue;
8309566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "vtk", &isVTK));
8310a96aa3bSJed Brown         if (isVTK) continue;
8329566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm, name));
8339566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm, name, &labelNew));
8349566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label, &defVal));
8359566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
8360a96aa3bSJed Brown       }
8370a96aa3bSJed Brown       /* map dm points (internal plex) to base
8380a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
8390a96aa3bSJed Brown          and propagating back to the coarsest
8400a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
8410a96aa3bSJed Brown          during DMForestTransferVecFromBase */
8429566063dSJacob Faibussowitsch       PetscCall(DMForestGetMinimumRefinement(dm, &l));
84348a46eb9SPierre Jolivet       if (!l) PetscCall(DMCreateLabel(dm, "_forest_base_subpoint_map"));
8440a96aa3bSJed Brown     }
8450a96aa3bSJed Brown   } else { /* construct from topology name */
8460a96aa3bSJed Brown     DMFTopology_pforest *topo;
8470a96aa3bSJed Brown 
8489566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreate_pforest(dm, topoName, &topo));
8490a96aa3bSJed Brown     pforest->topo = topo;
8500a96aa3bSJed Brown     /* TODO: construct base? */
8510a96aa3bSJed Brown   }
8520a96aa3bSJed Brown 
8530a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
8540a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
8550a96aa3bSJed Brown     DMLabel            adaptLabel;
8560a96aa3bSJed Brown     PetscInt           defaultValue;
8570a96aa3bSJed Brown     PetscInt           numValues, numValuesGlobal, cLocalStart, count;
8580a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest *)adaptFrom->data;
8590a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest *)aforest->data;
8600a96aa3bSJed Brown     PetscBool          computeAdaptSF;
8610a96aa3bSJed Brown     p4est_topidx_t     flt, llt, t;
8620a96aa3bSJed Brown 
8630a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
8640a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
8650a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
8669566063dSJacob Faibussowitsch     PetscCall(DMForestGetComputeAdaptivitySF(dm, &computeAdaptSF));
867792fecdfSBarry Smith     PetscCallP4estReturn(pforest->forest, p4est_copy, (apforest->forest, 0)); /* 0 indicates no data copying */
8689566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm, &adaptLabel));
8690a96aa3bSJed Brown     if (adaptLabel) {
8700a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
8719566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(adaptLabel, &numValues));
872712fec58SPierre Jolivet       PetscCall(MPIU_Allreduce(&numValues, &numValuesGlobal, 1, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)adaptFrom)));
8739566063dSJacob Faibussowitsch       PetscCall(DMLabelGetDefaultValue(adaptLabel, &defaultValue));
8740a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
8759566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8769566063dSJacob Faibussowitsch         PetscCall(DMPforestGetRefinementLevel(dm, &ctx.currLevel));
8770a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
878792fecdfSBarry Smith         PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_currlevel, NULL));
8790a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
880792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8810a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
88248a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), pforest->forest, 0, apforest->forest, apforest->cLocalStart, &coarseToPreFine, NULL));
8830a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */
8849566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
8850a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
886792fecdfSBarry Smith         PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_uniform, NULL));
8870a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
888792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8890a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
89048a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), pforest->forest, 0, apforest->forest, apforest->cLocalStart, &coarseToPreFine, NULL));
8910a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
8929566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &ctx.maxLevel));
8930a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
894792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 0, pforest_refine_uniform, NULL));
8950a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
896792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
8970a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
89848a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), apforest->forest, apforest->cLocalStart, pforest->forest, 0, &preCoarseToFine, NULL));
8990a96aa3bSJed Brown       } else if (numValuesGlobal) {
9000a96aa3bSJed Brown         p4est_t                   *p4est = pforest->forest;
9010a96aa3bSJed Brown         PetscInt                  *cellFlags;
9020a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
9030a96aa3bSJed Brown         PetscSF                    cellSF;
9040a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
9050a96aa3bSJed Brown         PetscBool                  adaptAny;
9060a96aa3bSJed Brown 
9079566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &ctx.maxLevel));
9089566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm, &ctx.minLevel));
9099566063dSJacob Faibussowitsch         PetscCall(DMForestGetAdaptivityStrategy(dm, &strategy));
9109566063dSJacob Faibussowitsch         PetscCall(PetscStrncmp(strategy, "any", 3, &adaptAny));
9119566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellChart(adaptFrom, &cStart, &cEnd));
9129566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellSF(adaptFrom, &cellSF));
9139566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cEnd - cStart, &cellFlags));
9149566063dSJacob Faibussowitsch         for (c = cStart; c < cEnd; c++) PetscCall(DMLabelGetValue(adaptLabel, c, &cellFlags[c - cStart]));
9150a96aa3bSJed Brown         if (cellSF) {
9160a96aa3bSJed Brown           if (adaptAny) {
9179566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MAX));
9189566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MAX));
9190a96aa3bSJed Brown           } else {
9209566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MIN));
9219566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF, MPIU_INT, cellFlags, cellFlags, MPI_MIN));
9220a96aa3bSJed Brown           }
9230a96aa3bSJed Brown         }
9240a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
9250a96aa3bSJed Brown           p4est_tree_t     *tree     = &(((p4est_tree_t *)p4est->trees->array)[t]);
9260a96aa3bSJed Brown           PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count, i;
9270a96aa3bSJed Brown           p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
9280a96aa3bSJed Brown 
9290a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9300a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
9310a96aa3bSJed Brown             q->p.user_int       = cellFlags[count++];
9320a96aa3bSJed Brown           }
9330a96aa3bSJed Brown         }
9349566063dSJacob Faibussowitsch         PetscCall(PetscFree(cellFlags));
9350a96aa3bSJed Brown 
9360a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)&ctx;
937792fecdfSBarry Smith         if (adaptAny) PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_flag_any, pforest_init_determine));
938792fecdfSBarry Smith         else PetscCallP4est(p4est_coarsen, (pforest->forest, 0, pforest_coarsen_flag_all, pforest_init_determine));
939792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 0, pforest_refine_flag, NULL));
9400a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
941792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
94248a46eb9SPierre Jolivet         if (computeAdaptSF) PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm), apforest->forest, apforest->cLocalStart, pforest->forest, 0, &preCoarseToFine, &coarseToPreFine));
9430a96aa3bSJed Brown       }
9440a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
9450a96aa3bSJed Brown         p4est_tree_t     *atree     = &(((p4est_tree_t *)apforest->forest->trees->array)[t]);
9460a96aa3bSJed Brown         p4est_tree_t     *tree      = &(((p4est_tree_t *)pforest->forest->trees->array)[t]);
9470a96aa3bSJed Brown         PetscInt          anumQuads = (PetscInt)atree->quadrants.elem_count, i;
9480a96aa3bSJed Brown         PetscInt          numQuads  = (PetscInt)tree->quadrants.elem_count;
9490a96aa3bSJed Brown         p4est_quadrant_t *aquads    = (p4est_quadrant_t *)atree->quadrants.array;
9500a96aa3bSJed Brown         p4est_quadrant_t *quads     = (p4est_quadrant_t *)tree->quadrants.array;
9510a96aa3bSJed Brown 
9520a96aa3bSJed Brown         if (anumQuads != numQuads) {
9530a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
9540a96aa3bSJed Brown         } else {
9550a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9560a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
9570a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
9580a96aa3bSJed Brown 
9590a96aa3bSJed Brown             if (aq->level != q->level) {
9600a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
9610a96aa3bSJed Brown               break;
9620a96aa3bSJed Brown             }
9630a96aa3bSJed Brown           }
9640a96aa3bSJed Brown         }
965ad540459SPierre Jolivet         if (ctx.anyChange) break;
9660a96aa3bSJed Brown       }
9670a96aa3bSJed Brown     }
9680a96aa3bSJed Brown     {
9690a96aa3bSJed Brown       PetscInt numLabels, l;
9700a96aa3bSJed Brown 
9719566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(adaptFrom, &numLabels));
9720a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
9730a96aa3bSJed Brown         PetscBool   isDepth, isCellType, isGhost, isVTK;
9740a96aa3bSJed Brown         DMLabel     label, labelNew;
9750a96aa3bSJed Brown         PetscInt    defVal;
9760a96aa3bSJed Brown         const char *name;
9770a96aa3bSJed Brown 
9789566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(adaptFrom, l, &name));
9799566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(adaptFrom, l, &label));
9809566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "depth", &isDepth));
9810a96aa3bSJed Brown         if (isDepth) continue;
9829566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "celltype", &isCellType));
9830a96aa3bSJed Brown         if (isCellType) continue;
9849566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "ghost", &isGhost));
9850a96aa3bSJed Brown         if (isGhost) continue;
9869566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name, "vtk", &isVTK));
9870a96aa3bSJed Brown         if (isVTK) continue;
9889566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm, name));
9899566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm, name, &labelNew));
9909566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label, &defVal));
9919566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew, defVal));
9920a96aa3bSJed Brown       }
9930a96aa3bSJed Brown     }
9940a96aa3bSJed Brown   } else { /* initial */
9950a96aa3bSJed Brown     PetscInt initLevel, minLevel;
99666c0a4b5SToby Isaac   #if defined(PETSC_HAVE_MPIUNI)
99766c0a4b5SToby Isaac     sc_MPI_Comm comm = sc_MPI_COMM_WORLD;
99866c0a4b5SToby Isaac   #else
99966c0a4b5SToby Isaac     MPI_Comm comm = PetscObjectComm((PetscObject)dm);
100066c0a4b5SToby Isaac   #endif
10010a96aa3bSJed Brown 
10029566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm, &initLevel));
10039566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
10049371c9d4SSatish Balay     PetscCallP4estReturn(pforest->forest, p4est_new_ext,
10059371c9d4SSatish Balay                          (comm, pforest->topo->conn, 0, /* minimum number of quadrants per processor */
10060a96aa3bSJed Brown                           initLevel,                    /* level of refinement */
10070a96aa3bSJed Brown                           1,                            /* uniform refinement */
10080a96aa3bSJed Brown                           0,                            /* we don't allocate any per quadrant data */
10090a96aa3bSJed Brown                           NULL,                         /* there is no special quadrant initialization */
10100a96aa3bSJed Brown                           (void *)dm));                 /* this dm is the user context */
10110a96aa3bSJed Brown 
10120a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10130a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
10140a96aa3bSJed Brown       PetscBool   flgPattern, flgFractal;
10150a96aa3bSJed Brown       PetscInt    corner = 0;
10160a96aa3bSJed Brown       PetscInt    corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
10170a96aa3bSJed Brown       PetscReal   likelihood = 1. / P4EST_DIM;
10180a96aa3bSJed Brown       PetscInt    pattern;
10190a96aa3bSJed Brown       const char *prefix;
10200a96aa3bSJed Brown 
10219566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
10229566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEList(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_pattern", DMRefinePatternName, PATTERN_COUNT, &pattern, &flgPattern));
10239566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_corner", &corner, NULL));
10249566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_fractal_corners", corners, &ncorner, &flgFractal));
10259566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options, prefix, "-dm_p4est_refine_hash_likelihood", &likelihood, NULL));
10260a96aa3bSJed Brown 
10270a96aa3bSJed Brown       if (flgPattern) {
10280a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
10290a96aa3bSJed Brown         PetscInt            maxLevel;
10300a96aa3bSJed Brown 
10319566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm, &maxLevel));
10324dfa11a4SJacob Faibussowitsch         PetscCall(PetscNew(&ctx));
10330a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel, P4EST_QMAXLEVEL);
10340a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10350a96aa3bSJed Brown         switch (pattern) {
10360a96aa3bSJed Brown         case PATTERN_HASH:
10370a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
10380a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
10390a96aa3bSJed Brown           break;
10400a96aa3bSJed Brown         case PATTERN_CORNER:
10410a96aa3bSJed Brown           ctx->corner    = corner;
10420a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
10430a96aa3bSJed Brown           break;
1044d71ae5a4SJacob Faibussowitsch         case PATTERN_CENTER:
1045d71ae5a4SJacob Faibussowitsch           ctx->refine_fn = DMRefinePattern_Center;
1046d71ae5a4SJacob Faibussowitsch           break;
10470a96aa3bSJed Brown         case PATTERN_FRACTAL:
10480a96aa3bSJed Brown           if (flgFractal) {
10490a96aa3bSJed Brown             PetscInt i;
10500a96aa3bSJed Brown 
10510a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
10520a96aa3bSJed Brown           } else {
10530a96aa3bSJed Brown   #if !defined(P4_TO_P8)
10540a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
10550a96aa3bSJed Brown   #else
10560a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
10570a96aa3bSJed Brown   #endif
10580a96aa3bSJed Brown           }
10590a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
10600a96aa3bSJed Brown           break;
1061d71ae5a4SJacob Faibussowitsch         default:
1062d71ae5a4SJacob Faibussowitsch           SETERRQ(PETSC_COMM_SELF, PETSC_ERR_ARG_OUTOFRANGE, "Not a valid refinement pattern");
10630a96aa3bSJed Brown         }
10640a96aa3bSJed Brown 
10650a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)ctx;
1066792fecdfSBarry Smith         PetscCallP4est(p4est_refine, (pforest->forest, 1, ctx->refine_fn, NULL));
1067792fecdfSBarry Smith         PetscCallP4est(p4est_balance, (pforest->forest, P4EST_CONNECT_FULL, NULL));
10689566063dSJacob Faibussowitsch         PetscCall(PetscFree(ctx));
10690a96aa3bSJed Brown         pforest->forest->user_pointer = (void *)dm;
10700a96aa3bSJed Brown       }
10710a96aa3bSJed Brown     }
10720a96aa3bSJed Brown   }
10730a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
10740a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
10750a96aa3bSJed Brown 
10769566063dSJacob Faibussowitsch     PetscCall(DMPforestGetRefinementLevel(dm, &currLevel));
10779566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm, &initLevel));
10789566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
1079156acca6SStefano Zampini     /* allow using PCMG and SNESFAS */
1080156acca6SStefano Zampini     PetscCall(DMSetRefineLevel(dm, currLevel - minLevel));
10810a96aa3bSJed Brown     if (currLevel > minLevel) {
10820a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
10830a96aa3bSJed Brown       DMLabel            coarsen;
10840a96aa3bSJed Brown       DM                 coarseDM;
10850a96aa3bSJed Brown 
10869566063dSJacob Faibussowitsch       PetscCall(DMForestTemplate(dm, MPI_COMM_NULL, &coarseDM));
10879566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityPurpose(coarseDM, DM_ADAPT_COARSEN));
10889566063dSJacob Faibussowitsch       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen", &coarsen));
10899566063dSJacob Faibussowitsch       PetscCall(DMLabelSetDefaultValue(coarsen, DM_ADAPT_COARSEN));
10909566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityLabel(coarseDM, coarsen));
10919566063dSJacob Faibussowitsch       PetscCall(DMLabelDestroy(&coarsen));
10929566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm, coarseDM));
10939566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)coarseDM));
10940a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
10959566063dSJacob Faibussowitsch       PetscCall(DMForestSetInitialRefinement(coarseDM, initLevel));
10969566063dSJacob Faibussowitsch       PetscCall(DMForestSetMinimumRefinement(coarseDM, minLevel));
10970a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest *)((DM_Forest *)coarseDM->data)->data;
10980a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
10990a96aa3bSJed Brown     }
11000a96aa3bSJed Brown   }
11010a96aa3bSJed Brown 
11020a96aa3bSJed Brown   { /* repartitioning and overlap */
11030a96aa3bSJed Brown     PetscMPIInt size, rank;
11040a96aa3bSJed Brown 
11059566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm), &size));
11069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
1107217f96c1SStefano Zampini     if (size > 1 && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
11080a96aa3bSJed Brown       PetscBool      copyForest  = PETSC_FALSE;
11090a96aa3bSJed Brown       p4est_t       *forest_copy = NULL;
11100a96aa3bSJed Brown       p4est_gloidx_t shipped     = 0;
11110a96aa3bSJed Brown 
11120a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
1113792fecdfSBarry Smith       if (copyForest) PetscCallP4estReturn(forest_copy, p4est_copy, (pforest->forest, 0));
11140a96aa3bSJed Brown 
11150a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
1116792fecdfSBarry Smith         PetscCallP4estReturn(shipped, p4est_partition_ext, (pforest->forest, (int)pforest->partition_for_coarsening, NULL));
11170a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_PLIB, "Non-uniform partition cases not implemented yet");
11180a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
11190a96aa3bSJed Brown       if (forest_copy) {
11200a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
11210a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
11220a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
11230a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
11240a96aa3bSJed Brown           PetscSFNode   *repartRoots;
11250a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
11260a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank + 1];
11270a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
11280a96aa3bSJed Brown 
11290a96aa3bSJed Brown           numRoots  = (PetscInt)(forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
11300a96aa3bSJed Brown           numLeaves = (PetscInt)(postEnd - postStart);
11319566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeOverlappingRanks(size, rank, pforest->forest, forest_copy, &pStart, &pEnd));
11329566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1((PetscInt)pforest->forest->local_num_quadrants, &repartRoots));
11330a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
11340a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
11350a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p + 1];
11360a96aa3bSJed Brown             PetscInt       q;
11370a96aa3bSJed Brown 
11380a96aa3bSJed Brown             if (preEnd == preStart) continue;
113908401ef6SPierre Jolivet             PetscCheck(preStart <= postStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Bad partition overlap computation");
11400a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
11410a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
11420a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
11430a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
11440a96aa3bSJed Brown             }
11450a96aa3bSJed Brown             partOffset = preEnd;
11460a96aa3bSJed Brown           }
11479566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &repartSF));
11489566063dSJacob Faibussowitsch           PetscCall(PetscSFSetGraph(repartSF, numRoots, numLeaves, NULL, PETSC_OWN_POINTER, repartRoots, PETSC_OWN_POINTER));
11499566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(repartSF));
11500a96aa3bSJed Brown           if (preCoarseToFine) {
11510a96aa3bSJed Brown             PetscSF         repartSFembed, preCoarseToFineNew;
11520a96aa3bSJed Brown             PetscInt        nleaves;
11530a96aa3bSJed Brown             const PetscInt *leaves;
11540a96aa3bSJed Brown 
11559566063dSJacob Faibussowitsch             PetscCall(PetscSFSetUp(preCoarseToFine));
11569566063dSJacob Faibussowitsch             PetscCall(PetscSFGetGraph(preCoarseToFine, NULL, &nleaves, &leaves, NULL));
11570a96aa3bSJed Brown             if (leaves) {
11589566063dSJacob Faibussowitsch               PetscCall(PetscSFCreateEmbeddedRootSF(repartSF, nleaves, leaves, &repartSFembed));
11590a96aa3bSJed Brown             } else {
11600a96aa3bSJed Brown               repartSFembed = repartSF;
11619566063dSJacob Faibussowitsch               PetscCall(PetscObjectReference((PetscObject)repartSFembed));
11620a96aa3bSJed Brown             }
11639566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(preCoarseToFine, repartSFembed, &preCoarseToFineNew));
11649566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&preCoarseToFine));
11659566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFembed));
11660a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
11670a96aa3bSJed Brown           }
11680a96aa3bSJed Brown           if (coarseToPreFine) {
11690a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
11700a96aa3bSJed Brown 
11719566063dSJacob Faibussowitsch             PetscCall(PetscSFCreateInverseSF(repartSF, &repartSFinv));
11729566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(repartSFinv, coarseToPreFine, &coarseToPreFineNew));
11739566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&coarseToPreFine));
11749566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFinv));
11750a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
11760a96aa3bSJed Brown           }
11779566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&repartSF));
11780a96aa3bSJed Brown         }
1179792fecdfSBarry Smith         PetscCallP4est(p4est_destroy, (forest_copy));
11800a96aa3bSJed Brown       }
11810a96aa3bSJed Brown     }
11820a96aa3bSJed Brown     if (size > 1) {
11830a96aa3bSJed Brown       PetscInt overlap;
11840a96aa3bSJed Brown 
11859566063dSJacob Faibussowitsch       PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
11860a96aa3bSJed Brown 
11870a96aa3bSJed Brown       if (adaptFrom) {
11880a96aa3bSJed Brown         PetscInt aoverlap;
11890a96aa3bSJed Brown 
11909566063dSJacob Faibussowitsch         PetscCall(DMForestGetPartitionOverlap(adaptFrom, &aoverlap));
1191ad540459SPierre Jolivet         if (aoverlap != overlap) ctx.anyChange = PETSC_TRUE;
11920a96aa3bSJed Brown       }
11930a96aa3bSJed Brown 
11940a96aa3bSJed Brown       if (overlap > 0) {
11950a96aa3bSJed Brown         PetscInt i, cLocalStart;
11960a96aa3bSJed Brown         PetscInt cEnd;
11970a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
11980a96aa3bSJed Brown 
1199792fecdfSBarry Smith         PetscCallP4estReturn(pforest->ghost, p4est_ghost_new, (pforest->forest, P4EST_CONNECT_FULL));
1200792fecdfSBarry Smith         PetscCallP4estReturn(pforest->lnodes, p4est_lnodes_new, (pforest->forest, pforest->ghost, -P4EST_DIM));
1201792fecdfSBarry Smith         PetscCallP4est(p4est_ghost_support_lnodes, (pforest->forest, pforest->lnodes, pforest->ghost));
1202792fecdfSBarry Smith         for (i = 1; i < overlap; i++) PetscCallP4est(p4est_ghost_expand_by_lnodes, (pforest->forest, pforest->lnodes, pforest->ghost));
12030a96aa3bSJed Brown 
12040a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
12050a96aa3bSJed Brown         cEnd                               = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
12060a96aa3bSJed Brown 
12070a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
12080a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
12099566063dSJacob Faibussowitsch           if (adaptFrom) PetscCall(DMForestGetCellSF(adaptFrom, &preCellSF));
12100a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
12119566063dSJacob Faibussowitsch           PetscCall(DMForestGetCellSF(dm, &cellSF));
12120a96aa3bSJed Brown         }
12130a96aa3bSJed Brown         if (preCoarseToFine) {
12140a96aa3bSJed Brown           PetscSF            preCoarseToFineNew;
12150a96aa3bSJed Brown           PetscInt           nleaves, nroots, *leavesNew, i, nleavesNew;
12160a96aa3bSJed Brown           const PetscInt    *leaves;
12170a96aa3bSJed Brown           const PetscSFNode *remotes;
12180a96aa3bSJed Brown           PetscSFNode       *remotesAll;
12190a96aa3bSJed Brown 
12209566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(preCoarseToFine));
12219566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCoarseToFine, &nroots, &nleaves, &leaves, &remotes));
12229566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(cEnd, &remotesAll));
12230a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
12240a96aa3bSJed Brown             remotesAll[i].rank  = -1;
12250a96aa3bSJed Brown             remotesAll[i].index = -1;
12260a96aa3bSJed Brown           }
12270a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
12289566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(cellSF));
12299566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(cellSF, MPIU_2INT, remotesAll, remotesAll, MPI_REPLACE));
12309566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(cellSF, MPIU_2INT, remotesAll, remotesAll, MPI_REPLACE));
12310a96aa3bSJed Brown           nleavesNew = 0;
12320a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12330a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
12340a96aa3bSJed Brown           }
12359566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesNew, &leavesNew));
12360a96aa3bSJed Brown           nleavesNew = 0;
12370a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12380a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
12390a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
12400a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
12410a96aa3bSJed Brown               nleavesNew++;
12420a96aa3bSJed Brown             }
12430a96aa3bSJed Brown           }
12449566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &preCoarseToFineNew));
12450a96aa3bSJed Brown           if (nleavesNew < cEnd) {
12469566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew, nroots, nleavesNew, leavesNew, PETSC_OWN_POINTER, remotesAll, PETSC_COPY_VALUES));
12470a96aa3bSJed Brown           } else { /* all cells are leaves */
12489566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
12499566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew, nroots, nleavesNew, NULL, PETSC_OWN_POINTER, remotesAll, PETSC_COPY_VALUES));
12500a96aa3bSJed Brown           }
12519566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesAll));
12529566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&preCoarseToFine));
12530a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12540a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12550a96aa3bSJed Brown         }
12560a96aa3bSJed Brown         if (coarseToPreFine) {
12570a96aa3bSJed Brown           PetscSF            coarseToPreFineNew;
12580a96aa3bSJed Brown           PetscInt           nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
12590a96aa3bSJed Brown           const PetscInt    *leaves;
12600a96aa3bSJed Brown           const PetscSFNode *remotes;
12610a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
12620a96aa3bSJed Brown 
12639566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(coarseToPreFine));
12649566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseToPreFine, &nroots, &nleaves, &leaves, &remotes));
12659566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCellSF, NULL, &nleavesCellSF, NULL, NULL));
12669566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nroots, &remotesNewRoot));
12679566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleaves, &remotesNew));
12680a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
12690a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
12700a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
12710a96aa3bSJed Brown           }
12729566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(coarseToPreFine, MPIU_2INT, remotesNewRoot, remotesNew, MPI_REPLACE));
12739566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(coarseToPreFine, MPIU_2INT, remotesNewRoot, remotesNew, MPI_REPLACE));
12749566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNewRoot));
12759566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesCellSF, &remotesExpanded));
12760a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12770a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
12780a96aa3bSJed Brown             remotesExpanded[i].index = -1;
12790a96aa3bSJed Brown           }
12800a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
12819566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNew));
12829566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(preCellSF, MPIU_2INT, remotesExpanded, remotesExpanded, MPI_REPLACE));
12839566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(preCellSF, MPIU_2INT, remotesExpanded, remotesExpanded, MPI_REPLACE));
12840a96aa3bSJed Brown 
12850a96aa3bSJed Brown           nleavesExpanded = 0;
12860a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12870a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
12880a96aa3bSJed Brown           }
12899566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesExpanded, &leavesNew));
12900a96aa3bSJed Brown           nleavesExpanded = 0;
12910a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12920a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
12930a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
12940a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
12950a96aa3bSJed Brown               nleavesExpanded++;
12960a96aa3bSJed Brown             }
12970a96aa3bSJed Brown           }
12989566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &coarseToPreFineNew));
12990a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
13009566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew, cEnd, nleavesExpanded, leavesNew, PETSC_OWN_POINTER, remotesExpanded, PETSC_COPY_VALUES));
13010a96aa3bSJed Brown           } else {
13029566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
13039566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew, cEnd, nleavesExpanded, NULL, PETSC_OWN_POINTER, remotesExpanded, PETSC_COPY_VALUES));
13040a96aa3bSJed Brown           }
13059566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesExpanded));
13069566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseToPreFine));
13070a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
13080a96aa3bSJed Brown         }
13090a96aa3bSJed Brown       }
13100a96aa3bSJed Brown     }
13110a96aa3bSJed Brown   }
13120a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
13130a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
13140a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
1315d72c4dc2SStefano Zampini   PetscCall(MPIU_Allreduce(&ctx.anyChange, &pforest->adaptivitySuccess, 1, MPIU_BOOL, MPI_LOR, PetscObjectComm((PetscObject)dm)));
13169566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, NULL));
13173ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13180a96aa3bSJed Brown }
13190a96aa3bSJed Brown 
13200a96aa3bSJed Brown   #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
1321d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success)
1322d71ae5a4SJacob Faibussowitsch {
13230a96aa3bSJed Brown   DM_Forest         *forest;
13240a96aa3bSJed Brown   DM_Forest_pforest *pforest;
13250a96aa3bSJed Brown 
13260a96aa3bSJed Brown   PetscFunctionBegin;
13270a96aa3bSJed Brown   forest   = (DM_Forest *)dm->data;
13280a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *)forest->data;
13290a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
13303ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13310a96aa3bSJed Brown }
13320a96aa3bSJed Brown 
13330a96aa3bSJed Brown   #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
1334d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer)
1335d71ae5a4SJacob Faibussowitsch {
13360a96aa3bSJed Brown   DM dm = (DM)odm;
13370a96aa3bSJed Brown 
13380a96aa3bSJed Brown   PetscFunctionBegin;
13390a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13400a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13419566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13420a96aa3bSJed Brown   switch (viewer->format) {
13430a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
13449371c9d4SSatish Balay   case PETSC_VIEWER_ASCII_INFO: {
13450a96aa3bSJed Brown     PetscInt    dim;
13460a96aa3bSJed Brown     const char *name;
13470a96aa3bSJed Brown 
13489566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)dm, &name));
13499566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
135063a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "Forest %s in %" PetscInt_FMT " dimensions:\n", name, dim));
135163a3b9bcSJacob Faibussowitsch     else PetscCall(PetscViewerASCIIPrintf(viewer, "Forest in %" PetscInt_FMT " dimensions:\n", dim));
1352f4d061e9SPierre Jolivet   } /* fall through */
13530a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
13549371c9d4SSatish Balay   case PETSC_VIEWER_LOAD_BALANCE: {
13550a96aa3bSJed Brown     DM plex;
13560a96aa3bSJed Brown 
13579566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dm, &plex));
13589566063dSJacob Faibussowitsch     PetscCall(DMView(plex, viewer));
13599371c9d4SSatish Balay   } break;
1360d71ae5a4SJacob Faibussowitsch   default:
1361d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13620a96aa3bSJed Brown   }
13633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
13640a96aa3bSJed Brown }
13650a96aa3bSJed Brown 
13660a96aa3bSJed Brown   #define DMView_VTK_pforest _append_pforest(DMView_VTK)
1367d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer)
1368d71ae5a4SJacob Faibussowitsch {
13690a96aa3bSJed Brown   DM                 dm      = (DM)odm;
13700a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
13710a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
13720a96aa3bSJed Brown   PetscBool          isvtk;
13730a96aa3bSJed Brown   PetscReal          vtkScale = 1. - PETSC_MACHINE_EPSILON;
13740a96aa3bSJed Brown   PetscViewer_VTK   *vtk      = (PetscViewer_VTK *)viewer->data;
13750a96aa3bSJed Brown   const char        *name;
13760a96aa3bSJed Brown   char              *filenameStrip = NULL;
13770a96aa3bSJed Brown   PetscBool          hasExt;
13780a96aa3bSJed Brown   size_t             len;
13790a96aa3bSJed Brown   p4est_geometry_t  *geom;
13800a96aa3bSJed Brown 
13810a96aa3bSJed Brown   PetscFunctionBegin;
13820a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13830a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13849566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13850a96aa3bSJed Brown   geom = pforest->topo->geom;
13869566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
138728b400f6SJacob Faibussowitsch   PetscCheck(isvtk, PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
13880a96aa3bSJed Brown   switch (viewer->format) {
13890a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
139028b400f6SJacob Faibussowitsch     PetscCheck(pforest->forest, PetscObjectComm(odm), PETSC_ERR_ARG_WRONG, "DM has not been setup with a valid forest");
13910a96aa3bSJed Brown     name = vtk->filename;
13929566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(name, &len));
13939566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(name + len - 4, ".vtu", &hasExt));
13940a96aa3bSJed Brown     if (hasExt) {
13959566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(name, &filenameStrip));
13960a96aa3bSJed Brown       filenameStrip[len - 4] = '\0';
13970a96aa3bSJed Brown       name                   = filenameStrip;
13980a96aa3bSJed Brown     }
1399792fecdfSBarry Smith     if (!pforest->topo->geom) PetscCallP4estReturn(geom, p4est_geometry_new_connectivity, (pforest->topo->conn));
14000a96aa3bSJed Brown     {
14010a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
14020a96aa3bSJed Brown       int                  footerr;
14030a96aa3bSJed Brown 
1404792fecdfSBarry Smith       PetscCallP4estReturn(pvtk, p4est_vtk_context_new, (pforest->forest, name));
1405792fecdfSBarry Smith       PetscCallP4est(p4est_vtk_context_set_geom, (pvtk, geom));
1406792fecdfSBarry Smith       PetscCallP4est(p4est_vtk_context_set_scale, (pvtk, (double)vtkScale));
1407792fecdfSBarry Smith       PetscCallP4estReturn(pvtk, p4est_vtk_write_header, (pvtk));
140828b400f6SJacob Faibussowitsch       PetscCheck(pvtk, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_header() failed");
14099371c9d4SSatish Balay       PetscCallP4estReturn(pvtk, p4est_vtk_write_cell_dataf,
14109371c9d4SSatish Balay                            (pvtk, 1, /* write tree */
14110a96aa3bSJed Brown                             1,       /* write level */
14120a96aa3bSJed Brown                             1,       /* write rank */
14130a96aa3bSJed Brown                             0,       /* do not wrap rank */
14140a96aa3bSJed Brown                             0,       /* no scalar fields */
14150a96aa3bSJed Brown                             0,       /* no vector fields */
14160a96aa3bSJed Brown                             pvtk));
141728b400f6SJacob Faibussowitsch       PetscCheck(pvtk, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_cell_dataf() failed");
1418792fecdfSBarry Smith       PetscCallP4estReturn(footerr, p4est_vtk_write_footer, (pvtk));
141928b400f6SJacob Faibussowitsch       PetscCheck(!footerr, PetscObjectComm((PetscObject)odm), PETSC_ERR_LIB, P4EST_STRING "_vtk_write_footer() failed");
14200a96aa3bSJed Brown     }
1421792fecdfSBarry Smith     if (!pforest->topo->geom) PetscCallP4est(p4est_geometry_destroy, (geom));
14229566063dSJacob Faibussowitsch     PetscCall(PetscFree(filenameStrip));
14230a96aa3bSJed Brown     break;
1424d71ae5a4SJacob Faibussowitsch   default:
1425d71ae5a4SJacob Faibussowitsch     SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
14260a96aa3bSJed Brown   }
14273ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14280a96aa3bSJed Brown }
14290a96aa3bSJed Brown 
14300a96aa3bSJed Brown   #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
1431d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer)
1432d71ae5a4SJacob Faibussowitsch {
14330a96aa3bSJed Brown   DM plex;
14340a96aa3bSJed Brown 
14350a96aa3bSJed Brown   PetscFunctionBegin;
14369566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14379566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14389566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14393ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14400a96aa3bSJed Brown }
14410a96aa3bSJed Brown 
14420a96aa3bSJed Brown   #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
1443d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer)
1444d71ae5a4SJacob Faibussowitsch {
14450a96aa3bSJed Brown   DM plex;
14460a96aa3bSJed Brown 
14470a96aa3bSJed Brown   PetscFunctionBegin;
14489566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14499566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14509566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14513ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14520a96aa3bSJed Brown }
14530a96aa3bSJed Brown 
14540a96aa3bSJed Brown   #define DMView_pforest _append_pforest(DMView)
1455d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer)
1456d71ae5a4SJacob Faibussowitsch {
14570a96aa3bSJed Brown   PetscBool isascii, isvtk, ishdf5, isglvis;
14580a96aa3bSJed Brown 
14590a96aa3bSJed Brown   PetscFunctionBegin;
14600a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14610a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
14629566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERASCII, &isascii));
14639566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERVTK, &isvtk));
14649566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERHDF5, &ishdf5));
14659566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)viewer, PETSCVIEWERGLVIS, &isglvis));
14660a96aa3bSJed Brown   if (isascii) {
14679566063dSJacob Faibussowitsch     PetscCall(DMView_ASCII_pforest((PetscObject)dm, viewer));
14680a96aa3bSJed Brown   } else if (isvtk) {
14699566063dSJacob Faibussowitsch     PetscCall(DMView_VTK_pforest((PetscObject)dm, viewer));
14700a96aa3bSJed Brown   } else if (ishdf5) {
14719566063dSJacob Faibussowitsch     PetscCall(DMView_HDF5_pforest(dm, viewer));
14720a96aa3bSJed Brown   } else if (isglvis) {
14739566063dSJacob Faibussowitsch     PetscCall(DMView_GLVis_pforest(dm, viewer));
14740a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Viewer not supported (not VTK, HDF5, or GLVis)");
14753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
14760a96aa3bSJed Brown }
14770a96aa3bSJed Brown 
1478d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq)
1479d71ae5a4SJacob Faibussowitsch {
14800a96aa3bSJed Brown   PetscInt *ttf, f, t, g, count;
14810a96aa3bSJed Brown   PetscInt  numFacets;
14820a96aa3bSJed Brown 
14830a96aa3bSJed Brown   PetscFunctionBegin;
14840a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
14859566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFacets, &ttf));
14860a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
14870a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
14880a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
14890a96aa3bSJed Brown       if (ttf[g] == -1) {
14900a96aa3bSJed Brown         PetscInt ng;
14910a96aa3bSJed Brown 
14920a96aa3bSJed Brown         ttf[g]  = count++;
14930a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
14940a96aa3bSJed Brown         ttf[ng] = ttf[g];
14950a96aa3bSJed Brown       }
14960a96aa3bSJed Brown     }
14970a96aa3bSJed Brown   }
14980a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
14993ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
15000a96aa3bSJed Brown }
15010a96aa3bSJed Brown 
1502d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq)
1503d71ae5a4SJacob Faibussowitsch {
15040a96aa3bSJed Brown   p4est_topidx_t numTrees, numVerts, numCorns, numCtt;
15050a96aa3bSJed Brown   PetscSection   ctt;
15060a96aa3bSJed Brown   #if defined(P4_TO_P8)
15070a96aa3bSJed Brown   p4est_topidx_t numEdges, numEtt;
15080a96aa3bSJed Brown   PetscSection   ett;
15090a96aa3bSJed Brown   PetscInt       eStart, eEnd, e, ettSize;
15100a96aa3bSJed Brown   PetscInt       vertOff = 1 + P4EST_FACES + P8EST_EDGES;
15110a96aa3bSJed Brown   PetscInt       edgeOff = 1 + P4EST_FACES;
15120a96aa3bSJed Brown   #else
15130a96aa3bSJed Brown   PetscInt vertOff = 1 + P4EST_FACES;
15140a96aa3bSJed Brown   #endif
15150a96aa3bSJed Brown   p4est_connectivity_t *conn;
15160a96aa3bSJed Brown   PetscInt              cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
15170a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
15180a96aa3bSJed Brown   PetscInt             *ttf;
15190a96aa3bSJed Brown 
15200a96aa3bSJed Brown   PetscFunctionBegin;
15210a96aa3bSJed Brown   /* 1: count objects, allocate */
15229566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 0, &cStart, &cEnd));
15239566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cEnd - cStart, &numTrees));
15240a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
15259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
15269566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(vEnd - vStart, &numCorns));
15279566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &ctt));
15289566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ctt, vStart, vEnd));
15290a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
15300a96aa3bSJed Brown     PetscInt s;
15310a96aa3bSJed Brown 
15329566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
15330a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15340a96aa3bSJed Brown       PetscInt p = star[2 * s];
15350a96aa3bSJed Brown 
15360a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15370a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
15380a96aa3bSJed Brown          * only protects against periodicity problems */
15399566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
154063a3b9bcSJacob 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);
15410a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
15420a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
15430a96aa3bSJed Brown 
15441dca8a05SBarry Smith           PetscCheck(cellVert >= vStart && cellVert < vEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure: vertices");
154548a46eb9SPierre Jolivet           if (cellVert == v) PetscCall(PetscSectionAddDof(ctt, v, 1));
15460a96aa3bSJed Brown         }
15479566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
15480a96aa3bSJed Brown       }
15490a96aa3bSJed Brown     }
15509566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
15510a96aa3bSJed Brown   }
15529566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ctt));
15539566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ctt, &cttSize));
15549566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cttSize, &numCtt));
15550a96aa3bSJed Brown   #if defined(P4_TO_P8)
15569566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, P4EST_DIM - 1, &eStart, &eEnd));
15579566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(eEnd - eStart, &numEdges));
15589566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &ett));
15599566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ett, eStart, eEnd));
15600a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
15610a96aa3bSJed Brown     PetscInt s;
15620a96aa3bSJed Brown 
15639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
15640a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15650a96aa3bSJed Brown       PetscInt p = star[2 * s];
15660a96aa3bSJed Brown 
15670a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15680a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
15690a96aa3bSJed Brown          * only protects against periodicity problems */
15709566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
157108401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_ARG_INCOMP, "Cell with wrong closure size");
15720a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
15730a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
15740a96aa3bSJed Brown 
15751dca8a05SBarry Smith           PetscCheck(cellEdge >= eStart && cellEdge < eEnd, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure: edges");
157648a46eb9SPierre Jolivet           if (cellEdge == e) PetscCall(PetscSectionAddDof(ett, e, 1));
15770a96aa3bSJed Brown         }
15789566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
15790a96aa3bSJed Brown       }
15800a96aa3bSJed Brown     }
15819566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
15820a96aa3bSJed Brown   }
15839566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ett));
15849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ett, &ettSize));
15859566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(ettSize, &numEtt));
15860a96aa3bSJed Brown 
15870a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
1588792fecdfSBarry Smith   PetscCallP4estReturn(conn, p8est_connectivity_new, (numVerts, numTrees, numEdges, numEtt, numCorns, numCtt));
15890a96aa3bSJed Brown   #else
1590792fecdfSBarry Smith   PetscCallP4estReturn(conn, p4est_connectivity_new, (numVerts, numTrees, numCorns, numCtt));
15910a96aa3bSJed Brown   #endif
15920a96aa3bSJed Brown 
15930a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
15949566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm, 1, &fStart, &fEnd));
15959566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((cEnd - cStart) * P4EST_FACES, &ttf));
15960a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
15970a96aa3bSJed Brown     PetscInt        numSupp, s;
15980a96aa3bSJed Brown     PetscInt        myFace[2] = {-1, -1};
15990a96aa3bSJed Brown     PetscInt        myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
16000a96aa3bSJed Brown     const PetscInt *supp;
16010a96aa3bSJed Brown 
16029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numSupp));
16031dca8a05SBarry 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);
16049566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &supp));
16050a96aa3bSJed Brown 
16060a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16070a96aa3bSJed Brown       PetscInt p = supp[s];
16080a96aa3bSJed Brown 
16090a96aa3bSJed Brown       if (p >= cEnd) {
16100a96aa3bSJed Brown         numSupp--;
16110a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
16120a96aa3bSJed Brown         break;
16130a96aa3bSJed Brown       }
16140a96aa3bSJed Brown     }
16150a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16160a96aa3bSJed Brown       PetscInt        p = supp[s], i;
16170a96aa3bSJed Brown       PetscInt        numCone;
16180a96aa3bSJed Brown       DMPolytopeType  ct;
16190a96aa3bSJed Brown       const PetscInt *cone;
16200a96aa3bSJed Brown       const PetscInt *ornt;
16210a96aa3bSJed Brown       PetscInt        orient = PETSC_MIN_INT;
16220a96aa3bSJed Brown 
16239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &numCone));
162463a3b9bcSJacob 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);
16259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
16269566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[0], &ct));
16279566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
16280a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
16290a96aa3bSJed Brown         if (cone[i] == f) {
16300a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
16310a96aa3bSJed Brown           break;
16320a96aa3bSJed Brown         }
16330a96aa3bSJed Brown       }
163463a3b9bcSJacob Faibussowitsch       PetscCheck(i < P4EST_FACES, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "cell %" PetscInt_FMT " faced %" PetscInt_FMT " mismatch", p, f);
16350a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
16360a96aa3bSJed Brown         DMPolytopeType ct;
16379566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
163863a3b9bcSJacob 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);
16390a96aa3bSJed Brown       }
16400a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
16410a96aa3bSJed Brown       if (numSupp == 1) {
16420a96aa3bSJed Brown         /* boundary faces indicated by self reference */
16430a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
16440a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t)PetscFaceToP4estFace[i];
16450a96aa3bSJed Brown       } else {
16460a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16470a96aa3bSJed Brown 
16480a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
16490a96aa3bSJed Brown         myFace[s]                                                                = PetscFaceToP4estFace[i];
16500a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
16510a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
16520a96aa3bSJed Brown         myOrnt[s] = DihedralCompose(N, orient, DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
16530a96aa3bSJed Brown       }
16540a96aa3bSJed Brown     }
16550a96aa3bSJed Brown     if (numSupp == 2) {
16560a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
16570a96aa3bSJed Brown         PetscInt       p = supp[s];
16580a96aa3bSJed Brown         PetscInt       orntAtoB;
16590a96aa3bSJed Brown         PetscInt       p4estOrient;
16600a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16610a96aa3bSJed Brown 
16620a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
16630a96aa3bSJed Brown          * permutation of this cell-facet's cone */
16640a96aa3bSJed Brown         orntAtoB = DihedralCompose(N, DihedralInvert(N, myOrnt[1 - s]), myOrnt[s]);
16650a96aa3bSJed Brown 
16660a96aa3bSJed Brown         /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
16670a96aa3bSJed Brown          * vertices around facet) */
16680a96aa3bSJed Brown   #if !defined(P4_TO_P8)
16690a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
16700a96aa3bSJed Brown   #else
16710a96aa3bSJed Brown         {
16720a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
16730a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
16740a96aa3bSJed Brown 
16750a96aa3bSJed Brown           /* swap bits */
16760a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
16770a96aa3bSJed Brown         }
16780a96aa3bSJed Brown   #endif
16790a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
16800a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
16810a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t)myFace[1 - s] + p4estOrient * P4EST_FACES;
16820a96aa3bSJed Brown       }
16830a96aa3bSJed Brown     }
16840a96aa3bSJed Brown   }
16850a96aa3bSJed Brown 
16860a96aa3bSJed Brown   #if defined(P4_TO_P8)
16870a96aa3bSJed Brown   /* 3: visit every edge */
16880a96aa3bSJed Brown   conn->ett_offset[0] = 0;
16890a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
16900a96aa3bSJed Brown     PetscInt off, s;
16910a96aa3bSJed Brown 
16929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ett, e, &off));
16930a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t)off;
16949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
16950a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
16960a96aa3bSJed Brown       PetscInt p = star[2 * s];
16970a96aa3bSJed Brown 
16980a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
16999566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
170008401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure");
17010a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
17020a96aa3bSJed Brown           PetscInt       cellEdge = closure[2 * (c + edgeOff)];
17030a96aa3bSJed Brown           PetscInt       cellOrnt = closure[2 * (c + edgeOff) + 1];
17040a96aa3bSJed Brown           DMPolytopeType ct;
17050a96aa3bSJed Brown 
17069566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cellEdge, &ct));
17070a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
17080a96aa3bSJed Brown           if (cellEdge == e) {
17090a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
17100a96aa3bSJed Brown             PetscInt totalOrient;
17110a96aa3bSJed Brown 
17120a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
17130a96aa3bSJed Brown             totalOrient = DihedralCompose(2, cellOrnt, DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
17140a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
17150a96aa3bSJed Brown             totalOrient             = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
17160a96aa3bSJed Brown             conn->edge_to_tree[off] = (p4est_locidx_t)(p - cStart);
1717d5b43468SJose E. Roman             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standard (see
17180a96aa3bSJed Brown              * p8est_connectivity.h) */
17190a96aa3bSJed Brown             conn->edge_to_edge[off++]                                  = (int8_t)p4estEdge + P8EST_EDGES * totalOrient;
17200a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
17210a96aa3bSJed Brown           }
17220a96aa3bSJed Brown         }
17239566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
17240a96aa3bSJed Brown       }
17250a96aa3bSJed Brown     }
17269566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, e, PETSC_FALSE, &starSize, &star));
17270a96aa3bSJed Brown   }
17289566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ett));
17290a96aa3bSJed Brown   #endif
17300a96aa3bSJed Brown 
17310a96aa3bSJed Brown   /* 4: visit every vertex */
17320a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
17330a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
17340a96aa3bSJed Brown     PetscInt off, s;
17350a96aa3bSJed Brown 
17369566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ctt, v, &off));
17370a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t)off;
17389566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
17390a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17400a96aa3bSJed Brown       PetscInt p = star[2 * s];
17410a96aa3bSJed Brown 
17420a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17439566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
174408401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Non-standard closure");
17450a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
17460a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
17470a96aa3bSJed Brown 
17480a96aa3bSJed Brown           if (cellVert == v) {
17490a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
17500a96aa3bSJed Brown 
17510a96aa3bSJed Brown             conn->corner_to_tree[off]                                       = (p4est_locidx_t)(p - cStart);
17520a96aa3bSJed Brown             conn->corner_to_corner[off++]                                   = (int8_t)p4estVert;
17530a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
17540a96aa3bSJed Brown           }
17550a96aa3bSJed Brown         }
17569566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm, p, PETSC_TRUE, &closureSize, &closure));
17570a96aa3bSJed Brown       }
17580a96aa3bSJed Brown     }
17599566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm, v, PETSC_FALSE, &starSize, &star));
17600a96aa3bSJed Brown   }
17619566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ctt));
17620a96aa3bSJed Brown 
17630a96aa3bSJed Brown   /* 5: Compute the coordinates */
17640a96aa3bSJed Brown   {
17650a96aa3bSJed Brown     PetscInt coordDim;
17660a96aa3bSJed Brown 
17679566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
17686858538eSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocalSetUp(dm));
17690a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
17700a96aa3bSJed Brown       PetscInt           dof;
17716858538eSMatthew G. Knepley       PetscBool          isDG;
17720a96aa3bSJed Brown       PetscScalar       *cellCoords = NULL;
17736858538eSMatthew G. Knepley       const PetscScalar *array;
17740a96aa3bSJed Brown 
17756858538eSMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17766858538eSMatthew 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);
17770a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
17780a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
17790a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
17800a96aa3bSJed Brown 
17810a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
17820a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
17830a96aa3bSJed Brown         for (i = 0; i < 3; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
17840a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
17850a96aa3bSJed Brown       }
17866858538eSMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17870a96aa3bSJed Brown     }
17880a96aa3bSJed Brown   }
17890a96aa3bSJed Brown 
17900a96aa3bSJed Brown   #if defined(P4EST_ENABLE_DEBUG)
179108401ef6SPierre Jolivet   PetscCheck(p4est_connectivity_is_valid(conn), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Plex to p4est conversion failed");
17920a96aa3bSJed Brown   #endif
17930a96aa3bSJed Brown 
17940a96aa3bSJed Brown   *connOut = conn;
17950a96aa3bSJed Brown 
17960a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
17973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
17980a96aa3bSJed Brown }
17990a96aa3bSJed Brown 
1800d71ae5a4SJacob Faibussowitsch static PetscErrorCode locidx_to_PetscInt(sc_array_t *array)
1801d71ae5a4SJacob Faibussowitsch {
18020a96aa3bSJed Brown   sc_array_t *newarray;
18030a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18040a96aa3bSJed Brown 
18050a96aa3bSJed Brown   PetscFunctionBegin;
180608401ef6SPierre Jolivet   PetscCheck(array->elem_size == sizeof(p4est_locidx_t), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong locidx size");
18070a96aa3bSJed Brown 
18083ba16761SJacob Faibussowitsch   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(PETSC_SUCCESS);
18090a96aa3bSJed Brown 
18100a96aa3bSJed Brown   newarray = sc_array_new_size(sizeof(PetscInt), array->elem_count);
18110a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18120a96aa3bSJed Brown     p4est_locidx_t il = *((p4est_locidx_t *)sc_array_index(array, zz));
18130a96aa3bSJed Brown     PetscInt      *ip = (PetscInt *)sc_array_index(newarray, zz);
18140a96aa3bSJed Brown 
18150a96aa3bSJed Brown     *ip = (PetscInt)il;
18160a96aa3bSJed Brown   }
18170a96aa3bSJed Brown 
18180a96aa3bSJed Brown   sc_array_reset(array);
18190a96aa3bSJed Brown   sc_array_init_size(array, sizeof(PetscInt), count);
18200a96aa3bSJed Brown   sc_array_copy(array, newarray);
18210a96aa3bSJed Brown   sc_array_destroy(newarray);
18223ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18230a96aa3bSJed Brown }
18240a96aa3bSJed Brown 
1825d71ae5a4SJacob Faibussowitsch static PetscErrorCode coords_double_to_PetscScalar(sc_array_t *array, PetscInt dim)
1826d71ae5a4SJacob Faibussowitsch {
18270a96aa3bSJed Brown   sc_array_t *newarray;
18280a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18290a96aa3bSJed Brown 
18300a96aa3bSJed Brown   PetscFunctionBegin;
18311dca8a05SBarry Smith   PetscCheck(array->elem_size == 3 * sizeof(double), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong coordinate size");
18320a96aa3bSJed Brown   #if !defined(PETSC_USE_COMPLEX)
18333ba16761SJacob Faibussowitsch   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(PETSC_SUCCESS);
18340a96aa3bSJed Brown   #endif
18350a96aa3bSJed Brown 
18360a96aa3bSJed Brown   newarray = sc_array_new_size(dim * sizeof(PetscScalar), array->elem_count);
18370a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18380a96aa3bSJed Brown     int          i;
18390a96aa3bSJed Brown     double      *id = (double *)sc_array_index(array, zz);
18400a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar *)sc_array_index(newarray, zz);
18410a96aa3bSJed Brown 
18420a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
18430a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim, 3); i++) ip[i] = (PetscScalar)id[i];
18440a96aa3bSJed Brown   }
18450a96aa3bSJed Brown 
18460a96aa3bSJed Brown   sc_array_reset(array);
18470a96aa3bSJed Brown   sc_array_init_size(array, dim * sizeof(PetscScalar), count);
18480a96aa3bSJed Brown   sc_array_copy(array, newarray);
18490a96aa3bSJed Brown   sc_array_destroy(newarray);
18503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18510a96aa3bSJed Brown }
18520a96aa3bSJed Brown 
1853d71ae5a4SJacob Faibussowitsch static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t *array)
1854d71ae5a4SJacob Faibussowitsch {
18550a96aa3bSJed Brown   sc_array_t *newarray;
18560a96aa3bSJed Brown   size_t      zz, count = array->elem_count;
18570a96aa3bSJed Brown 
18580a96aa3bSJed Brown   PetscFunctionBegin;
18591dca8a05SBarry Smith   PetscCheck(array->elem_size == 2 * sizeof(p4est_locidx_t), PETSC_COMM_SELF, PETSC_ERR_PLIB, "Wrong locidx size");
18600a96aa3bSJed Brown 
18610a96aa3bSJed Brown   newarray = sc_array_new_size(sizeof(PetscSFNode), array->elem_count);
18620a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18630a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t *)sc_array_index(array, zz);
18640a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode *)sc_array_index(newarray, zz);
18650a96aa3bSJed Brown 
18660a96aa3bSJed Brown     ip->rank  = (PetscInt)il[0];
18670a96aa3bSJed Brown     ip->index = (PetscInt)il[1];
18680a96aa3bSJed Brown   }
18690a96aa3bSJed Brown 
18700a96aa3bSJed Brown   sc_array_reset(array);
18710a96aa3bSJed Brown   sc_array_init_size(array, sizeof(PetscSFNode), count);
18720a96aa3bSJed Brown   sc_array_copy(array, newarray);
18730a96aa3bSJed Brown   sc_array_destroy(newarray);
18743ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
18750a96aa3bSJed Brown }
18760a96aa3bSJed Brown 
1877d71ae5a4SJacob Faibussowitsch static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM *plex)
1878d71ae5a4SJacob Faibussowitsch {
18790a96aa3bSJed Brown   PetscFunctionBegin;
18800a96aa3bSJed Brown   {
18810a96aa3bSJed Brown     sc_array_t    *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
18820a96aa3bSJed Brown     sc_array_t    *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
18830a96aa3bSJed Brown     sc_array_t    *cones             = sc_array_new(sizeof(p4est_locidx_t));
18840a96aa3bSJed Brown     sc_array_t    *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
18850a96aa3bSJed Brown     sc_array_t    *coords            = sc_array_new(3 * sizeof(double));
18860a96aa3bSJed Brown     sc_array_t    *children          = sc_array_new(sizeof(p4est_locidx_t));
18870a96aa3bSJed Brown     sc_array_t    *parents           = sc_array_new(sizeof(p4est_locidx_t));
18880a96aa3bSJed Brown     sc_array_t    *childids          = sc_array_new(sizeof(p4est_locidx_t));
18890a96aa3bSJed Brown     sc_array_t    *leaves            = sc_array_new(sizeof(p4est_locidx_t));
18900a96aa3bSJed Brown     sc_array_t    *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
18910a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
18920a96aa3bSJed Brown 
1893792fecdfSBarry 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));
18940a96aa3bSJed Brown 
18959566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
18969566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
18979566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
18989566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
18999566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, P4EST_DIM));
19000a96aa3bSJed Brown 
19019566063dSJacob Faibussowitsch     PetscCall(DMPlexCreate(PETSC_COMM_SELF, plex));
19029566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(*plex, P4EST_DIM));
19039566063dSJacob 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));
19049566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(*plex));
19050a96aa3bSJed Brown     sc_array_destroy(points_per_dim);
19060a96aa3bSJed Brown     sc_array_destroy(cone_sizes);
19070a96aa3bSJed Brown     sc_array_destroy(cones);
19080a96aa3bSJed Brown     sc_array_destroy(cone_orientations);
19090a96aa3bSJed Brown     sc_array_destroy(coords);
19100a96aa3bSJed Brown     sc_array_destroy(children);
19110a96aa3bSJed Brown     sc_array_destroy(parents);
19120a96aa3bSJed Brown     sc_array_destroy(childids);
19130a96aa3bSJed Brown     sc_array_destroy(leaves);
19140a96aa3bSJed Brown     sc_array_destroy(remotes);
19150a96aa3bSJed Brown   }
19163ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
19170a96aa3bSJed Brown }
19180a96aa3bSJed Brown 
19190a96aa3bSJed Brown   #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
1920d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB, PetscInt *childB)
1921d71ae5a4SJacob Faibussowitsch {
19220a96aa3bSJed Brown   PetscInt coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
19230a96aa3bSJed Brown 
19240a96aa3bSJed Brown   PetscFunctionBegin;
19250a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
19260a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
19270a96aa3bSJed Brown     if (childB) *childB = childA;
19283ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19290a96aa3bSJed Brown   }
19309566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm, 0, &vStart, &vEnd));
19316aad120cSJose E. Roman   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invariant under rotation */
19320a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
19330a96aa3bSJed Brown     if (childB) *childB = childA;
19343ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19350a96aa3bSJed Brown   }
19360a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
19379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm, dim, &dStart, &dEnd));
19380a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
19390a96aa3bSJed Brown   }
194063a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2, PETSC_COMM_SELF, PETSC_ERR_SUP, "Cannot perform child symmetry for %" PetscInt_FMT "-cells", dim);
194128b400f6SJacob Faibussowitsch   PetscCheck(dim, PETSC_COMM_SELF, PETSC_ERR_PLIB, "A vertex has no children");
19420a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
19430a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
19440a96aa3bSJed Brown     PetscInt        size, i, sA = -1, sB, sOrientB, sConeSize;
19450a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
19460a96aa3bSJed Brown 
19479566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, childA, &size));
19489566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, childA, &supp));
19490a96aa3bSJed Brown 
19500a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
19510a96aa3bSJed Brown     for (i = 0; i < size; i++) {
19520a96aa3bSJed Brown       PetscInt sParent;
19530a96aa3bSJed Brown 
19540a96aa3bSJed Brown       sA = supp[i];
19550a96aa3bSJed Brown       if (sA == parent) continue;
19569566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm, sA, &sParent, NULL));
19570a96aa3bSJed Brown       if (sParent == parent) break;
19580a96aa3bSJed Brown     }
195908401ef6SPierre Jolivet     PetscCheck(i != size, PETSC_COMM_SELF, PETSC_ERR_PLIB, "could not find support in children");
19600a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
19610a96aa3bSJed Brown      * parentOrientB */
19629566063dSJacob Faibussowitsch     PetscCall(DMReferenceTreeGetChildSymmetry_pforest(dm, parent, parentOrientA, 0, sA, parentOrientB, &sOrientB, &sB));
19639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm, sA, &sConeSize));
19649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sA, &coneA));
19659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm, sB, &coneB));
19669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sA, &oA));
19679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm, sB, &oB));
19680a96aa3bSJed Brown     /* step through the cone of sA in natural order */
19690a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
19700a96aa3bSJed Brown       if (coneA[i] == childA) {
19710a96aa3bSJed Brown         /* if childA is at position i in coneA,
19720a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
19730a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize - (sOrientB + 1) - i) % sConeSize);
19740a96aa3bSJed Brown         if (childB) *childB = coneB[j];
19750a96aa3bSJed Brown         if (childOrientB) {
19760a96aa3bSJed Brown           DMPolytopeType ct;
19770a96aa3bSJed Brown           PetscInt       oBtrue;
19780a96aa3bSJed Brown 
19799566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm, childA, &coneSize));
19800a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
19811dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Expected a vertex or an edge");
19820a96aa3bSJed Brown           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
19830a96aa3bSJed Brown           /* we may have to flip an edge */
19840a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
19850a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
19860a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize, DMPolytopeConvertNewOrientation_Internal(ct, oA[i]), oBtrue);
19870a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
19880a96aa3bSJed Brown         }
19890a96aa3bSJed Brown         break;
19900a96aa3bSJed Brown       }
19910a96aa3bSJed Brown     }
199208401ef6SPierre Jolivet     PetscCheck(i != sConeSize, PETSC_COMM_SELF, PETSC_ERR_PLIB, "support cone mismatch");
19933ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
19940a96aa3bSJed Brown   }
19950a96aa3bSJed Brown   /* get the cone size and symmetry swap */
19969566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm, parent, &coneSize));
19970a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
19980a96aa3bSJed Brown   if (dim == 2) {
19990a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
20000a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
20010a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
20020a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
20030a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
20040a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
20050a96aa3bSJed Brown   } else {
20060a96aa3bSJed Brown     oAvert     = parentOrientA;
20070a96aa3bSJed Brown     oBvert     = parentOrientB;
20080a96aa3bSJed Brown     ABswapVert = ABswap;
20090a96aa3bSJed Brown   }
20100a96aa3bSJed Brown   if (childB) {
20110a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
20120a96aa3bSJed Brown     PetscInt        p, posA = -1, numChildren, i;
20130a96aa3bSJed Brown     const PetscInt *children;
20140a96aa3bSJed Brown 
20150a96aa3bSJed Brown     /* count which position the child is in */
20169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm, parent, &numChildren, &children));
20170a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
20180a96aa3bSJed Brown       p = children[i];
20190a96aa3bSJed Brown       if (p == childA) {
20200a96aa3bSJed Brown         if (dim == 1) {
20210a96aa3bSJed Brown           posA = i;
20220a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
20230a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
20240a96aa3bSJed Brown         }
20250a96aa3bSJed Brown         break;
20260a96aa3bSJed Brown       }
20270a96aa3bSJed Brown     }
20280a96aa3bSJed Brown     if (posA >= coneSize) {
20290a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF, PETSC_ERR_PLIB, "Could not find childA in children of parent");
20300a96aa3bSJed Brown     } else {
20310a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
20320a96aa3bSJed Brown       PetscInt posB, childIdB;
20330a96aa3bSJed Brown 
20340a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize - (ABswapVert + 1) - posA) % coneSize);
20350a96aa3bSJed Brown       if (dim == 1) {
20360a96aa3bSJed Brown         childIdB = posB;
20370a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
20380a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
20390a96aa3bSJed Brown       }
20400a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
20410a96aa3bSJed Brown     }
20420a96aa3bSJed Brown   }
20430a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize, childOrientA, ABswap);
20443ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
20450a96aa3bSJed Brown }
20460a96aa3bSJed Brown 
20470a96aa3bSJed Brown   #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
2048d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm)
2049d71ae5a4SJacob Faibussowitsch {
20500a96aa3bSJed Brown   p4est_connectivity_t *refcube;
20510a96aa3bSJed Brown   p4est_t              *root, *refined;
20520a96aa3bSJed Brown   DM                    dmRoot, dmRefined;
20530a96aa3bSJed Brown   DM_Plex              *mesh;
20540a96aa3bSJed Brown   PetscMPIInt           rank;
205566c0a4b5SToby Isaac   #if defined(PETSC_HAVE_MPIUNI)
205666c0a4b5SToby Isaac   sc_MPI_Comm comm_self = sc_MPI_COMM_SELF;
205766c0a4b5SToby Isaac   #else
205866c0a4b5SToby Isaac   MPI_Comm comm_self = PETSC_COMM_SELF;
205966c0a4b5SToby Isaac   #endif
20600a96aa3bSJed Brown 
20610a96aa3bSJed Brown   PetscFunctionBegin;
2062792fecdfSBarry Smith   PetscCallP4estReturn(refcube, p4est_connectivity_new_byname, ("unit"));
20630a96aa3bSJed Brown   { /* [-1,1]^d geometry */
20640a96aa3bSJed Brown     PetscInt i, j;
20650a96aa3bSJed Brown 
20660a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
20670a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
20680a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
20690a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
20700a96aa3bSJed Brown       }
20710a96aa3bSJed Brown     }
20720a96aa3bSJed Brown   }
2073792fecdfSBarry Smith   PetscCallP4estReturn(root, p4est_new, (comm_self, refcube, 0, NULL, NULL));
2074792fecdfSBarry Smith   PetscCallP4estReturn(refined, p4est_new_ext, (comm_self, refcube, 0, 1, 1, 0, NULL, NULL));
20759566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(root, &dmRoot));
20769566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(refined, &dmRefined));
20770a96aa3bSJed Brown   {
20780a96aa3bSJed Brown   #if !defined(P4_TO_P8)
20790a96aa3bSJed Brown     PetscInt nPoints   = 25;
20809371c9d4SSatish 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};
20819371c9d4SSatish 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};
20820a96aa3bSJed Brown   #else
20830a96aa3bSJed Brown     PetscInt nPoints    = 125;
20849371c9d4SSatish 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,
20859371c9d4SSatish 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,
20869371c9d4SSatish 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};
20879371c9d4SSatish 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,
20889371c9d4SSatish 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};
20890a96aa3bSJed Brown 
20900a96aa3bSJed Brown   #endif
20910a96aa3bSJed Brown     IS permIS;
20920a96aa3bSJed Brown     DM dmPerm;
20930a96aa3bSJed Brown 
20949566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF, nPoints, perm, PETSC_USE_POINTER, &permIS));
20959566063dSJacob Faibussowitsch     PetscCall(DMPlexPermute(dmRefined, permIS, &dmPerm));
20960a96aa3bSJed Brown     if (dmPerm) {
20979566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmRefined));
20980a96aa3bSJed Brown       dmRefined = dmPerm;
20990a96aa3bSJed Brown     }
21009566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
21010a96aa3bSJed Brown     {
21020a96aa3bSJed Brown       PetscInt p;
21039566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRoot, "identity"));
21049566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRefined, "identity"));
210548a46eb9SPierre Jolivet       for (p = 0; p < P4EST_INSUL; p++) PetscCall(DMSetLabelValue(dmRoot, "identity", p, p));
210648a46eb9SPierre Jolivet       for (p = 0; p < nPoints; p++) PetscCall(DMSetLabelValue(dmRefined, "identity", p, ident[p]));
21070a96aa3bSJed Brown     }
21080a96aa3bSJed Brown   }
21099566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(dmRoot, dmRefined, "identity", dm));
21100a96aa3bSJed Brown   mesh                   = (DM_Plex *)(*dm)->data;
21110a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
21129566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
21130a96aa3bSJed Brown   if (rank == 0) {
21149566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRoot, NULL, "-dm_p4est_ref_root_view"));
21159566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined, NULL, "-dm_p4est_ref_refined_view"));
21169566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined, NULL, "-dm_p4est_ref_tree_view"));
21170a96aa3bSJed Brown   }
21189566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRefined));
21199566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRoot));
2120792fecdfSBarry Smith   PetscCallP4est(p4est_destroy, (refined));
2121792fecdfSBarry Smith   PetscCallP4est(p4est_destroy, (root));
2122792fecdfSBarry Smith   PetscCallP4est(p4est_connectivity_destroy, (refcube));
21233ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21240a96aa3bSJed Brown }
21250a96aa3bSJed Brown 
2126d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB)
2127d71ae5a4SJacob Faibussowitsch {
21280a96aa3bSJed Brown   void     *ctx;
21290a96aa3bSJed Brown   PetscInt  num;
21300a96aa3bSJed Brown   PetscReal val;
21310a96aa3bSJed Brown 
21320a96aa3bSJed Brown   PetscFunctionBegin;
21339566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmA, &ctx));
21349566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dmB, ctx));
21359566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmA, dmB));
21369566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dmA, &num, &val));
21379566063dSJacob Faibussowitsch   PetscCall(DMSetOutputSequenceNumber(dmB, num, val));
21380a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
21399566063dSJacob Faibussowitsch     PetscCall(DMClearLocalVectors(dmB));
21409566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->localSection));
2141*f4f49eeaSPierre Jolivet     PetscCall(PetscSectionDestroy(&dmB->localSection));
21420a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
21439566063dSJacob Faibussowitsch     PetscCall(DMClearGlobalVectors(dmB));
21449566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->globalSection));
2145*f4f49eeaSPierre Jolivet     PetscCall(PetscSectionDestroy(&dmB->globalSection));
21460a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
21479566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.section));
2148*f4f49eeaSPierre Jolivet     PetscCall(PetscSectionDestroy(&dmB->defaultConstraint.section));
21493b8ba7d1SJed Brown     dmB->defaultConstraint.section = dmA->defaultConstraint.section;
21509566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.mat));
2151*f4f49eeaSPierre Jolivet     PetscCall(MatDestroy(&dmB->defaultConstraint.mat));
21523b8ba7d1SJed Brown     dmB->defaultConstraint.mat = dmA->defaultConstraint.mat;
21539566063dSJacob Faibussowitsch     if (dmA->map) PetscCall(PetscLayoutReference(dmA->map, &dmB->map));
21540a96aa3bSJed Brown   }
21550a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
21569566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->sectionSF));
21579566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&dmB->sectionSF));
21580a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
21590a96aa3bSJed Brown   }
21603ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
21610a96aa3bSJed Brown }
21620a96aa3bSJed Brown 
21630a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
2164d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm, p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF)
2165d71ae5a4SJacob Faibussowitsch {
21660a96aa3bSJed Brown   PetscInt     startF, endF, startC, endC, p, nLeaves;
21670a96aa3bSJed Brown   PetscSFNode *leaves;
21680a96aa3bSJed Brown   PetscSF      sf;
21690a96aa3bSJed Brown   PetscInt    *recv, *send;
21700a96aa3bSJed Brown   PetscMPIInt  tag;
21710a96aa3bSJed Brown   MPI_Request *recvReqs, *sendReqs;
21720a96aa3bSJed Brown   PetscSection section;
21730a96aa3bSJed Brown 
21740a96aa3bSJed Brown   PetscFunctionBegin;
21759566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize, p4estC->mpirank, p4estF, p4estC, &startC, &endC));
21769566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2 * (endC - startC), &recv, endC - startC, &recvReqs));
21779566063dSJacob Faibussowitsch   PetscCall(PetscCommGetNewTag(comm, &tag));
21780a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
21790a96aa3bSJed Brown     recvReqs[p - startC] = MPI_REQUEST_NULL;                                        /* just in case we don't initiate a receive */
21800a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p + 1]) { /* empty coarse partition */
21810a96aa3bSJed Brown       recv[2 * (p - startC)]     = 0;
21820a96aa3bSJed Brown       recv[2 * (p - startC) + 1] = 0;
21830a96aa3bSJed Brown       continue;
21840a96aa3bSJed Brown     }
21850a96aa3bSJed Brown 
21869566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(&recv[2 * (p - startC)], 2, MPIU_INT, p, tag, comm, &recvReqs[p - startC]));
21870a96aa3bSJed Brown   }
21889566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize, p4estC->mpirank, p4estC, p4estF, &startF, &endF));
21899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2 * (endF - startF), &send, endF - startF, &sendReqs));
21900a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
21910a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
21920a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
21930a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p + 1];
21940a96aa3bSJed Brown     PetscInt          tStart      = (PetscInt)myFineStart->p.which_tree;
21950a96aa3bSJed Brown     PetscInt          tEnd        = (PetscInt)myFineEnd->p.which_tree;
21960a96aa3bSJed Brown     PetscInt          firstCell = -1, lastCell = -1;
21970a96aa3bSJed Brown     p4est_tree_t     *treeStart = &(((p4est_tree_t *)p4estC->trees->array)[tStart]);
21980a96aa3bSJed Brown     p4est_tree_t     *treeEnd   = (size_t)tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t *)p4estC->trees->array)[tEnd]) : NULL;
21990a96aa3bSJed Brown     ssize_t           overlapIndex;
22000a96aa3bSJed Brown 
22010a96aa3bSJed Brown     sendReqs[p - startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
22020a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p + 1]) continue;
22030a96aa3bSJed Brown 
22040a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
22050a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
2206*f4f49eeaSPierre Jolivet       PetscCallP4estReturn(overlapIndex, sc_array_bsearch, (&treeStart->quadrants, myFineStart, p4est_quadrant_disjoint));
22070a96aa3bSJed Brown       if (overlapIndex < 0) {
22080a96aa3bSJed Brown         firstCell = 0;
22090a96aa3bSJed Brown       } else {
22100a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
22110a96aa3bSJed Brown       }
22120a96aa3bSJed Brown     } else {
22130a96aa3bSJed Brown       firstCell = 0;
22140a96aa3bSJed Brown     }
22150a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
2216*f4f49eeaSPierre Jolivet       PetscCallP4estReturn(overlapIndex, sc_array_bsearch, (&treeEnd->quadrants, myFineEnd, p4est_quadrant_disjoint));
22170a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
22180a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
22190a96aa3bSJed Brown       } else {
22200a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t *)treeEnd->quadrants.array)[overlapIndex]);
22210a96aa3bSJed Brown         p4est_quadrant_t  first_desc;
22220a96aa3bSJed Brown         int               equal;
22230a96aa3bSJed Brown 
2224792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_first_descendant, (container, &first_desc, P4EST_QMAXLEVEL));
2225792fecdfSBarry Smith         PetscCallP4estReturn(equal, p4est_quadrant_is_equal, (myFineEnd, &first_desc));
22260a96aa3bSJed Brown         if (equal) {
22270a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
22280a96aa3bSJed Brown         } else {
22290a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
22300a96aa3bSJed Brown         }
22310a96aa3bSJed Brown       }
22320a96aa3bSJed Brown     } else {
22330a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
22340a96aa3bSJed Brown     }
22350a96aa3bSJed Brown     send[2 * (p - startF)]     = firstCell;
22360a96aa3bSJed Brown     send[2 * (p - startF) + 1] = lastCell - firstCell;
22379566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(&send[2 * (p - startF)], 2, MPIU_INT, p, tag, comm, &sendReqs[p - startF]));
22380a96aa3bSJed Brown   }
22399566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endC - startC), recvReqs, MPI_STATUSES_IGNORE));
22409566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &section));
22419566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section, startC, endC));
22420a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22430a96aa3bSJed Brown     PetscInt numCells = recv[2 * (p - startC) + 1];
22449566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section, p, numCells));
22450a96aa3bSJed Brown   }
22469566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
22479566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section, &nLeaves));
22489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nLeaves, &leaves));
22490a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22500a96aa3bSJed Brown     PetscInt firstCell = recv[2 * (p - startC)];
22510a96aa3bSJed Brown     PetscInt numCells  = recv[2 * (p - startC) + 1];
22520a96aa3bSJed Brown     PetscInt off, i;
22530a96aa3bSJed Brown 
22549566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section, p, &off));
22550a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
22560a96aa3bSJed Brown       leaves[off + i].rank  = p;
22570a96aa3bSJed Brown       leaves[off + i].index = firstCell + i;
22580a96aa3bSJed Brown     }
22590a96aa3bSJed Brown   }
22609566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm, &sf));
22619566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, cEnd - cStart, nLeaves, NULL, PETSC_OWN_POINTER, leaves, PETSC_OWN_POINTER));
22629566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
22639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endF - startF), sendReqs, MPI_STATUSES_IGNORE));
22649566063dSJacob Faibussowitsch   PetscCall(PetscFree2(send, sendReqs));
22659566063dSJacob Faibussowitsch   PetscCall(PetscFree2(recv, recvReqs));
22660a96aa3bSJed Brown   *coveringSF = sf;
22673ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
22680a96aa3bSJed Brown }
22690a96aa3bSJed Brown 
22700a96aa3bSJed Brown /* closure points for locally-owned cells */
2271d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints, PetscBool redirect)
2272d71ae5a4SJacob Faibussowitsch {
22730a96aa3bSJed Brown   PetscInt           cStart, cEnd;
22740a96aa3bSJed Brown   PetscInt           count, c;
22750a96aa3bSJed Brown   PetscMPIInt        rank;
22760a96aa3bSJed Brown   PetscInt           closureSize = -1;
22770a96aa3bSJed Brown   PetscInt          *closure     = NULL;
22780a96aa3bSJed Brown   PetscSF            pointSF;
22790a96aa3bSJed Brown   PetscInt           nleaves, nroots;
22800a96aa3bSJed Brown   const PetscInt    *ilocal;
22810a96aa3bSJed Brown   const PetscSFNode *iremote;
22820a96aa3bSJed Brown   DM                 plex;
22830a96aa3bSJed Brown   DM_Forest         *forest;
22840a96aa3bSJed Brown   DM_Forest_pforest *pforest;
22850a96aa3bSJed Brown 
22860a96aa3bSJed Brown   PetscFunctionBegin;
22870a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
22880a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
22890a96aa3bSJed Brown   cStart  = pforest->cLocalStart;
22900a96aa3bSJed Brown   cEnd    = pforest->cLocalEnd;
22919566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
22929566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm, &pointSF));
22939566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(pointSF, &nroots, &nleaves, &ilocal, &iremote));
22940a96aa3bSJed Brown   nleaves           = PetscMax(0, nleaves);
22950a96aa3bSJed Brown   nroots            = PetscMax(0, nroots);
22960a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
22979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numClosurePoints, closurePoints));
22989566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
22990a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
23000a96aa3bSJed Brown     PetscInt i;
23019566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(plex, c, PETSC_TRUE, &closureSize, &closure));
23020a96aa3bSJed Brown 
23030a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
23040a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
23050a96aa3bSJed Brown       PetscInt loc = -1;
23060a96aa3bSJed Brown 
23079566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(p, nleaves, ilocal, &loc));
23080a96aa3bSJed Brown       if (redirect && loc >= 0) {
23090a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
23100a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
23110a96aa3bSJed Brown       } else {
23120a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
23130a96aa3bSJed Brown         (*closurePoints)[count].index = p;
23140a96aa3bSJed Brown       }
23150a96aa3bSJed Brown     }
23169566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(plex, c, PETSC_TRUE, &closureSize, &closure));
23170a96aa3bSJed Brown   }
23183ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
23190a96aa3bSJed Brown }
23200a96aa3bSJed Brown 
2321d71ae5a4SJacob Faibussowitsch static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type)
2322d71ae5a4SJacob Faibussowitsch {
23230a96aa3bSJed Brown   PetscMPIInt i;
23240a96aa3bSJed Brown 
23250a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
23260a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode *)a;
23270a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode *)b;
23280a96aa3bSJed Brown 
23290a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
23300a96aa3bSJed Brown   }
23310a96aa3bSJed Brown }
23320a96aa3bSJed Brown 
2333d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
2334d71ae5a4SJacob Faibussowitsch {
23350a96aa3bSJed Brown   MPI_Comm           comm;
23360a96aa3bSJed Brown   PetscMPIInt        rank, size;
23370a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
23380a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
23390a96aa3bSJed Brown   PetscInt           numClosureIndices;
23400a96aa3bSJed Brown   PetscInt           numClosurePointsC, numClosurePointsF;
23410a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
23420a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
23430a96aa3bSJed Brown   p4est_quadrant_t **treeQuads;
23440a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
23450a96aa3bSJed Brown   MPI_Datatype       nodeType;
23460a96aa3bSJed Brown   MPI_Datatype       nodeClosureType;
23470a96aa3bSJed Brown   MPI_Op             sfNodeReduce;
23480a96aa3bSJed Brown   p4est_topidx_t     fltF, lltF, t;
23490a96aa3bSJed Brown   DM                 plexC, plexF;
23500a96aa3bSJed Brown   PetscInt           pStartF, pEndF, pStartC, pEndC;
23510a96aa3bSJed Brown   PetscBool          saveInCoarse = PETSC_FALSE;
23520a96aa3bSJed Brown   PetscBool          saveInFine   = PETSC_FALSE;
23530a96aa3bSJed Brown   PetscBool          formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
23540a96aa3bSJed Brown   PetscInt          *cids         = NULL;
23550a96aa3bSJed Brown 
23560a96aa3bSJed Brown   PetscFunctionBegin;
23570a96aa3bSJed Brown   pforestC = (DM_Forest_pforest *)((DM_Forest *)coarse->data)->data;
23580a96aa3bSJed Brown   pforestF = (DM_Forest_pforest *)((DM_Forest *)fine->data)->data;
23590a96aa3bSJed Brown   p4estC   = pforestC->forest;
23600a96aa3bSJed Brown   p4estF   = pforestF->forest;
236108401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo, PetscObjectComm((PetscObject)coarse), PETSC_ERR_ARG_INCOMP, "DM's must have the same base DM");
23620a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
23639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
23649566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm, &size));
23659566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine, &plexF));
23669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF, &pStartF, &pEndF));
23679566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse, &plexC));
23689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC, &pStartC, &pEndC));
23690a96aa3bSJed Brown   { /* check if the results have been cached */
23700a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
23710a96aa3bSJed Brown 
23729566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(coarse, &adaptCoarse));
23739566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(fine, &adaptFine));
23740a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
23750a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
2376*f4f49eeaSPierre Jolivet         PetscCall(PetscObjectReference((PetscObject)pforestC->pointSelfToAdaptSF));
23770a96aa3bSJed Brown         *sf = pforestC->pointSelfToAdaptSF;
23780a96aa3bSJed Brown         if (childIds) {
23799566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
23809566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids, pforestC->pointSelfToAdaptCids, pEndF - pStartF));
23810a96aa3bSJed Brown           *childIds = cids;
23820a96aa3bSJed Brown         }
23833ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
23840a96aa3bSJed Brown       } else {
23850a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
23860a96aa3bSJed Brown         formCids     = PETSC_TRUE;
23870a96aa3bSJed Brown       }
23880a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
23890a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
2390*f4f49eeaSPierre Jolivet         PetscCall(PetscObjectReference((PetscObject)pforestF->pointAdaptToSelfSF));
23910a96aa3bSJed Brown         *sf = pforestF->pointAdaptToSelfSF;
23920a96aa3bSJed Brown         if (childIds) {
23939566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
23949566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids, pforestF->pointAdaptToSelfCids, pEndF - pStartF));
23950a96aa3bSJed Brown           *childIds = cids;
23960a96aa3bSJed Brown         }
23973ba16761SJacob Faibussowitsch         PetscFunctionReturn(PETSC_SUCCESS);
23980a96aa3bSJed Brown       } else {
23990a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
24000a96aa3bSJed Brown         formCids   = PETSC_TRUE;
24010a96aa3bSJed Brown       }
24020a96aa3bSJed Brown     }
24030a96aa3bSJed Brown   }
24040a96aa3bSJed Brown 
24050a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
24060a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
24070a96aa3bSJed Brown   /* create the datatype */
24089566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(2, MPIU_INT, &nodeType));
24099566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
24109566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_create(DMPforestMaxSFNode, PETSC_FALSE, &sfNodeReduce));
24119566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(numClosureIndices * 2, MPIU_INT, &nodeClosureType));
24129566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeClosureType));
24130a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
24140a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
24159566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(coarse, numClosureIndices, &numClosurePointsC, &closurePointsC, PETSC_TRUE));
24169566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(fine, numClosureIndices, &numClosurePointsF, &closurePointsF, PETSC_FALSE));
24170a96aa3bSJed Brown   /* create pointers for tree lists */
24180a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
24190a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
24209566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(lltF + 1 - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts));
24210a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
24220a96aa3bSJed Brown   if (size > 1) {
24230a96aa3bSJed Brown     PetscInt p;
24240a96aa3bSJed Brown 
24250a96aa3bSJed Brown     for (p = 0; p < size; p++) {
24260a96aa3bSJed Brown       int equal;
24270a96aa3bSJed Brown 
2428792fecdfSBarry Smith       PetscCallP4estReturn(equal, p4est_quadrant_is_equal_piggy, (&p4estC->global_first_position[p], &p4estF->global_first_position[p]));
24290a96aa3bSJed Brown       if (!equal) break;
24300a96aa3bSJed Brown     }
24310a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
24320a96aa3bSJed Brown       PetscInt          cStartC, cEndC;
24330a96aa3bSJed Brown       PetscSF           coveringSF;
24340a96aa3bSJed Brown       PetscInt          nleaves;
24350a96aa3bSJed Brown       PetscInt          count;
24360a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
24370a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
24380a96aa3bSJed Brown       p4est_topidx_t    fltC = p4estC->first_local_tree;
24390a96aa3bSJed Brown       p4est_topidx_t    lltC = p4estC->last_local_tree;
24400a96aa3bSJed Brown       p4est_topidx_t    t;
24410a96aa3bSJed Brown       PetscMPIInt       blockSizes[4]   = {P4EST_DIM, 2, 1, 1};
24429371c9d4SSatish 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)};
24430a96aa3bSJed Brown       MPI_Datatype      blockTypes[4]   = {MPI_INT32_T, MPI_INT8_T, MPI_INT16_T, MPI_INT32_T /* p.which_tree */};
24440a96aa3bSJed Brown       MPI_Datatype      quadStruct, quadType;
24450a96aa3bSJed Brown 
24469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC, 0, &cStartC, &cEndC));
24479566063dSJacob Faibussowitsch       PetscCall(DMPforestGetCellCoveringSF(comm, p4estC, p4estF, pforestC->cLocalStart, pforestC->cLocalEnd, &coveringSF));
24489566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coveringSF, NULL, &nleaves, NULL, NULL));
24499566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numClosureIndices * nleaves, &newClosurePointsC));
24509566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &coverQuads));
24519566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cEndC - cStartC, &coverQuadsSend));
24520a96aa3bSJed Brown       count = 0;
24530a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
24540a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t *)p4estC->trees->array)[t]);
24550a96aa3bSJed Brown         PetscInt      q;
24560a96aa3bSJed Brown 
24579566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&coverQuadsSend[count], tree->quadrants.array, tree->quadrants.elem_count * sizeof(p4est_quadrant_t)));
24580a96aa3bSJed Brown         for (q = 0; (size_t)q < tree->quadrants.elem_count; q++) coverQuadsSend[count + q].p.which_tree = t;
24590a96aa3bSJed Brown         count += tree->quadrants.elem_count;
24600a96aa3bSJed Brown       }
24610a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
24620a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
24630a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
24640a96aa3bSJed Brown        */
24659566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_struct(4, blockSizes, blockOffsets, blockTypes, &quadStruct));
24669566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_resized(quadStruct, 0, sizeof(p4est_quadrant_t), &quadType));
24679566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&quadType));
24689566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF, nodeClosureType, closurePointsC, newClosurePointsC, MPI_REPLACE));
24699566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF, quadType, coverQuadsSend, coverQuads, MPI_REPLACE));
24709566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF, nodeClosureType, closurePointsC, newClosurePointsC, MPI_REPLACE));
24719566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF, quadType, coverQuadsSend, coverQuads, MPI_REPLACE));
24729566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadStruct));
24739566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadType));
24749566063dSJacob Faibussowitsch       PetscCall(PetscFree(coverQuadsSend));
24759566063dSJacob Faibussowitsch       PetscCall(PetscFree(closurePointsC));
24769566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coveringSF));
24770a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
24780a96aa3bSJed Brown 
24790a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
24800a96aa3bSJed Brown       {
24810a96aa3bSJed Brown         PetscInt q;
24820a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
24830a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
24840a96aa3bSJed Brown           if (!treeQuadCounts[t - fltF]++) treeQuads[t - fltF] = &coverQuads[q];
24850a96aa3bSJed Brown         }
24860a96aa3bSJed Brown       }
24870a96aa3bSJed Brown     }
24880a96aa3bSJed Brown   }
24890a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
24900a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
24910a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t *)p4estC->trees->array)[t]);
24920a96aa3bSJed Brown 
24930a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
24940a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t *)tree->quadrants.array;
24950a96aa3bSJed Brown     }
24960a96aa3bSJed Brown   }
24970a96aa3bSJed Brown 
24980a96aa3bSJed Brown   {
24990a96aa3bSJed Brown     PetscInt     p;
25000a96aa3bSJed Brown     PetscInt     cLocalStartF;
25010a96aa3bSJed Brown     PetscSF      pointSF;
25020a96aa3bSJed Brown     PetscSFNode *roots;
25030a96aa3bSJed Brown     PetscInt    *rootType;
25040a96aa3bSJed Brown     DM           refTree = NULL;
25050a96aa3bSJed Brown     DMLabel      canonical;
25060a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
25070a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
25080a96aa3bSJed Brown     PetscInt     coarseOffset;
25090a96aa3bSJed Brown     PetscInt     numCoarseQuads;
25100a96aa3bSJed Brown 
25119566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF - pStartF, &roots));
25129566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF - pStartF, &rootType));
25139566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(fine, &pointSF));
25140a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
25150a96aa3bSJed Brown       roots[p - pStartF].rank  = -1;
25160a96aa3bSJed Brown       roots[p - pStartF].index = -1;
25170a96aa3bSJed Brown       rootType[p - pStartF]    = -1;
25180a96aa3bSJed Brown     }
25190a96aa3bSJed Brown     if (formCids) {
25200a96aa3bSJed Brown       PetscInt child;
25210a96aa3bSJed Brown 
25229566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &cids));
25230a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
25249566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF, &refTree));
25259566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(refTree, 0, PETSC_TRUE, NULL, &rootClosure));
25260a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
25279566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree, child + 1, PETSC_TRUE, NULL, &childClosures[child]));
25280a96aa3bSJed Brown       }
25299566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(refTree, "canonical", &canonical));
25300a96aa3bSJed Brown     }
25310a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
25320a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
25330a96aa3bSJed Brown       p4est_tree_t     *tree         = &(((p4est_tree_t *)p4estF->trees->array)[t]);
25340a96aa3bSJed Brown       PetscInt          numFineQuads = tree->quadrants.elem_count;
25350a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads  = treeQuads[t - fltF];
25360a96aa3bSJed Brown       p4est_quadrant_t *fineQuads    = (p4est_quadrant_t *)tree->quadrants.array;
25370a96aa3bSJed Brown       PetscInt          i, coarseCount = 0;
25380a96aa3bSJed Brown       PetscInt          offset = tree->quadrants_offset;
25390a96aa3bSJed Brown       sc_array_t        coarseQuadsArray;
25400a96aa3bSJed Brown 
25410a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
2542792fecdfSBarry Smith       PetscCallP4est(sc_array_init_data, (&coarseQuadsArray, coarseQuads, sizeof(p4est_quadrant_t), (size_t)numCoarseQuads));
25430a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
25440a96aa3bSJed Brown         PetscInt          c          = i + offset;
25450a96aa3bSJed Brown         p4est_quadrant_t *quad       = &fineQuads[i];
25460a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
25470a96aa3bSJed Brown         ssize_t           disjoint   = -1;
25480a96aa3bSJed Brown 
25490a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
25500a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
2551792fecdfSBarry Smith           PetscCallP4estReturn(disjoint, p4est_quadrant_disjoint, (quadCoarse, quad));
25520a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
25530a96aa3bSJed Brown         }
255408401ef6SPierre Jolivet         PetscCheck(disjoint == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "did not find overlapping coarse quad");
25550a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
25560a96aa3bSJed Brown           if (transferIdent) {                                                                         /* find corners */
25570a96aa3bSJed Brown             PetscInt j = 0;
25580a96aa3bSJed Brown 
25590a96aa3bSJed Brown             do {
25600a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
25610a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
25620a96aa3bSJed Brown                 int              equal;
25630a96aa3bSJed Brown 
2564792fecdfSBarry Smith                 PetscCallP4est(p4est_quadrant_corner_descendant, (quad, &cornerQuad, j, quadCoarse->level));
2565792fecdfSBarry Smith                 PetscCallP4estReturn(equal, p4est_quadrant_is_equal, (&cornerQuad, quadCoarse));
25660a96aa3bSJed Brown                 if (equal) {
25670a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
25680a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
25690a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
25700a96aa3bSJed Brown 
25710a96aa3bSJed Brown                   roots[p - pStartF]    = q;
25720a96aa3bSJed Brown                   rootType[p - pStartF] = PETSC_MAX_INT;
25730a96aa3bSJed Brown                   cids[p - pStartF]     = -1;
25740a96aa3bSJed Brown                   j++;
25750a96aa3bSJed Brown                 }
25760a96aa3bSJed Brown               }
25770a96aa3bSJed Brown               coarseCount++;
25780a96aa3bSJed Brown               disjoint = 1;
25790a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
25800a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
2581792fecdfSBarry Smith                 PetscCallP4estReturn(disjoint, p4est_quadrant_disjoint, (quadCoarse, quad));
25820a96aa3bSJed Brown               }
25830a96aa3bSJed Brown             } while (!disjoint);
25840a96aa3bSJed Brown           }
25850a96aa3bSJed Brown           continue;
25860a96aa3bSJed Brown         }
25870a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
25880a96aa3bSJed Brown           PetscInt j;
25890a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
25900a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
25910a96aa3bSJed Brown 
25920a96aa3bSJed Brown             roots[p - pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
25930a96aa3bSJed Brown             rootType[p - pStartF] = PETSC_MAX_INT; /* unconditionally accept */
25940a96aa3bSJed Brown             cids[p - pStartF]     = -1;
25950a96aa3bSJed Brown           }
25960a96aa3bSJed Brown         } else {
25970a96aa3bSJed Brown           PetscInt levelDiff                 = quad->level - quadCoarse->level;
25980a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
25990a96aa3bSJed Brown 
26000a96aa3bSJed Brown           if (formCids) {
26010a96aa3bSJed Brown             PetscInt  cl;
26020a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
26030a96aa3bSJed Brown             int       cid;
26040a96aa3bSJed Brown 
260508401ef6SPierre Jolivet             PetscCheck(levelDiff <= 1, PETSC_COMM_SELF, PETSC_ERR_USER, "Recursive child ids not implemented");
2606792fecdfSBarry Smith             PetscCallP4estReturn(cid, p4est_quadrant_child_id, (quad));
26079566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(plexF, c + cLocalStartF, PETSC_TRUE, NULL, &pointClosure));
26080a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
26090a96aa3bSJed Brown               PetscInt       p      = pointClosure[2 * cl];
26100a96aa3bSJed Brown               PetscInt       point  = childClosures[cid][2 * cl];
26110a96aa3bSJed Brown               PetscInt       ornt   = childClosures[cid][2 * cl + 1];
26120a96aa3bSJed Brown               PetscInt       newcid = -1;
26130a96aa3bSJed Brown               DMPolytopeType ct;
26140a96aa3bSJed Brown 
26150a96aa3bSJed Brown               if (rootType[p - pStartF] == PETSC_MAX_INT) continue;
26169566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCellType(refTree, point, &ct));
26170a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
26180a96aa3bSJed Brown               if (!cl) {
26190a96aa3bSJed Brown                 newcid = cid + 1;
26200a96aa3bSJed Brown               } else {
26210a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
26220a96aa3bSJed Brown 
26239566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetTreeParent(refTree, point, &parent, NULL));
26240a96aa3bSJed Brown                 if (parent == point) {
26250a96aa3bSJed Brown                   newcid = -1;
26260a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
26270a96aa3bSJed Brown                   newcid = point;
26280a96aa3bSJed Brown                 } else {
26290a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
26300a96aa3bSJed Brown 
26310a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
26320a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
26339566063dSJacob Faibussowitsch                       PetscCall(DMPlexGetCellType(refTree, parent, &rct));
26340a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
26350a96aa3bSJed Brown                       break;
26360a96aa3bSJed Brown                     }
26370a96aa3bSJed Brown                   }
263808401ef6SPierre Jolivet                   PetscCheck(rcl < P4EST_INSUL, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Couldn't find parent in root closure");
26399566063dSJacob Faibussowitsch                   PetscCall(DMPlexReferenceTreeGetChildSymmetry(refTree, parent, parentOrnt, ornt, point, DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]), NULL, &newcid));
26400a96aa3bSJed Brown                 }
26410a96aa3bSJed Brown               }
26420a96aa3bSJed Brown               if (newcid >= 0) {
264348a46eb9SPierre Jolivet                 if (canonical) PetscCall(DMLabelGetValue(canonical, newcid, &newcid));
26440a96aa3bSJed Brown                 proposedCids[cl] = newcid;
26450a96aa3bSJed Brown               }
26460a96aa3bSJed Brown             }
26479566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(plexF, c + cLocalStartF, PETSC_TRUE, NULL, &pointClosure));
26480a96aa3bSJed Brown           }
26499371c9d4SSatish Balay           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {
26509371c9d4SSatish Balay             {quadCoarse->x, quadCoarse->y,
26510a96aa3bSJed Brown   #if defined(P4_TO_P8)
26520a96aa3bSJed Brown              quadCoarse->z
26530a96aa3bSJed Brown   #endif
26549371c9d4SSatish Balay             },
26559371c9d4SSatish Balay             {0}
26569371c9d4SSatish Balay           };
26579371c9d4SSatish Balay           p4est_qcoord_t fineBound[2][P4EST_DIM] = {
26589371c9d4SSatish Balay             {quad->x, quad->y,
26590a96aa3bSJed Brown   #if defined(P4_TO_P8)
26600a96aa3bSJed Brown              quad->z
26610a96aa3bSJed Brown   #endif
26629371c9d4SSatish Balay             },
26639371c9d4SSatish Balay             {0}
26649371c9d4SSatish Balay           };
26650a96aa3bSJed Brown           PetscInt j;
26660a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
26670a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
26680a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j] + P4EST_QUADRANT_LEN(quad->level);
26690a96aa3bSJed Brown           }
26700a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
26710a96aa3bSJed Brown             PetscInt    l, p;
26720a96aa3bSJed Brown             PetscSFNode q;
26730a96aa3bSJed Brown 
26740a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
26750a96aa3bSJed Brown             if (rootType[p - pStartF] == PETSC_MAX_INT) continue;
26760a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
26770a96aa3bSJed Brown               l = 0;
26780a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
26790a96aa3bSJed Brown               PetscInt face       = PetscFaceToP4estFace[j - 1];
26800a96aa3bSJed Brown               PetscInt direction  = face / 2;
26810a96aa3bSJed Brown               PetscInt coarseFace = -1;
26820a96aa3bSJed Brown 
26830a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
26840a96aa3bSJed Brown                 coarseFace = face;
26850a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
26860a96aa3bSJed Brown               } else {
26870a96aa3bSJed Brown                 l = 0;
26880a96aa3bSJed Brown               }
26890a96aa3bSJed Brown   #if defined(P4_TO_P8)
26900a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
26910a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
26920a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
26930a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
26940a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
26950a96aa3bSJed Brown               PetscInt  minDir = PetscMin((direction + 1) % 3, (direction + 2) % 3);
26960a96aa3bSJed Brown               PetscInt  maxDir = PetscMax((direction + 1) % 3, (direction + 2) % 3);
26970a96aa3bSJed Brown               PetscBool dirTest[2];
26980a96aa3bSJed Brown 
26990a96aa3bSJed Brown               dirTest[0] = (PetscBool)(coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
27000a96aa3bSJed Brown               dirTest[1] = (PetscBool)(coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
27010a96aa3bSJed Brown 
27020a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
27030a96aa3bSJed Brown                 coarseEdge = edge;
27040a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27050a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
27060a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
27070a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
27080a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
27090a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
27100a96aa3bSJed Brown                 l          = 1 + P4estFaceToPetscFace[coarseFace];
27110a96aa3bSJed Brown               } else {
27120a96aa3bSJed Brown                 l = 0;
27130a96aa3bSJed Brown               }
27140a96aa3bSJed Brown   #endif
27150a96aa3bSJed Brown             } else {
27160a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
27170a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
27180a96aa3bSJed Brown               PetscInt  m;
27190a96aa3bSJed Brown               PetscInt  numMatch     = 0;
27200a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
27210a96aa3bSJed Brown   #if defined(P4_TO_P8)
27220a96aa3bSJed Brown               PetscInt coarseEdge = -1;
27230a96aa3bSJed Brown   #endif
27240a96aa3bSJed Brown 
27250a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
27260a96aa3bSJed Brown                 dirTest[m] = (PetscBool)(coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
27270a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
27280a96aa3bSJed Brown               }
27290a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
27300a96aa3bSJed Brown                 coarseVertex = vertex;
27310a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
27320a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
27330a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27340a96aa3bSJed Brown                   if (dirTest[m]) {
27350a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
27360a96aa3bSJed Brown                     break;
27370a96aa3bSJed Brown                   }
27380a96aa3bSJed Brown                 }
27390a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27400a96aa3bSJed Brown   #if defined(P4_TO_P8)
27410a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
27420a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27430a96aa3bSJed Brown                   if (!dirTest[m]) {
27440a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
27450a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
27460a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1, otherDir2);
27470a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1, otherDir2);
27480a96aa3bSJed Brown 
27490a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
27500a96aa3bSJed Brown                     break;
27510a96aa3bSJed Brown                   }
27520a96aa3bSJed Brown                 }
27530a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27540a96aa3bSJed Brown   #endif
27550a96aa3bSJed Brown               } else { /* volume */
27560a96aa3bSJed Brown                 l = 0;
27570a96aa3bSJed Brown               }
27580a96aa3bSJed Brown             }
27590a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
27600a96aa3bSJed Brown             if (l > rootType[p - pStartF]) {
27610a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
27620a96aa3bSJed Brown                 if (transferIdent) {
27630a96aa3bSJed Brown                   roots[p - pStartF]    = q;
27640a96aa3bSJed Brown                   rootType[p - pStartF] = PETSC_MAX_INT;
27650a96aa3bSJed Brown                   if (formCids) cids[p - pStartF] = -1;
27660a96aa3bSJed Brown                 }
27670a96aa3bSJed Brown               } else {
27680a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
27690a96aa3bSJed Brown 
27700a96aa3bSJed Brown                 roots[p - pStartF]    = q;
27710a96aa3bSJed Brown                 rootType[p - pStartF] = l;
27720a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
27730a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
27740a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
27750a96aa3bSJed Brown                   PetscInt parent;
27760a96aa3bSJed Brown 
27779566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetTreeParent(plexF, thisp, &parent, NULL));
27780a96aa3bSJed Brown                   if (parent == thisp) break;
27790a96aa3bSJed Brown 
27800a96aa3bSJed Brown                   roots[parent - pStartF]    = q;
27810a96aa3bSJed Brown                   rootType[parent - pStartF] = PETSC_MAX_INT;
27820a96aa3bSJed Brown                   if (formCids) cids[parent - pStartF] = -1;
27830a96aa3bSJed Brown                   thisp = parent;
27840a96aa3bSJed Brown                 }
27850a96aa3bSJed Brown               }
27860a96aa3bSJed Brown             }
27870a96aa3bSJed Brown           }
27880a96aa3bSJed Brown         }
27890a96aa3bSJed Brown       }
27900a96aa3bSJed Brown     }
27910a96aa3bSJed Brown 
27920a96aa3bSJed 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 */
27930a96aa3bSJed Brown     if (size > 1) {
27940a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
27950a96aa3bSJed Brown 
27969566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &rootTypeCopy));
27979566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(rootTypeCopy, rootType, pEndF - pStartF));
279857168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_MAX));
279957168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_MAX));
28009566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_REPLACE));
28019566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, rootTypeCopy, rootTypeCopy, MPI_REPLACE));
28020a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28030a96aa3bSJed 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 */
28040a96aa3bSJed Brown           roots[p - pStartF].rank  = -1;
28050a96aa3bSJed Brown           roots[p - pStartF].index = -1;
28060a96aa3bSJed Brown         }
28079371c9d4SSatish 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 */ }
28080a96aa3bSJed Brown       }
28099566063dSJacob Faibussowitsch       PetscCall(PetscFree(rootTypeCopy));
28109566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF, nodeType, roots, roots, sfNodeReduce));
28119566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF, nodeType, roots, roots, sfNodeReduce));
28129566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, nodeType, roots, roots, MPI_REPLACE));
28139566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, nodeType, roots, roots, MPI_REPLACE));
28140a96aa3bSJed Brown     }
28159566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootType));
28160a96aa3bSJed Brown 
28170a96aa3bSJed Brown     {
28180a96aa3bSJed Brown       PetscInt     numRoots;
28190a96aa3bSJed Brown       PetscInt     numLeaves;
28200a96aa3bSJed Brown       PetscInt    *leaves;
28210a96aa3bSJed Brown       PetscSFNode *iremote;
28220a96aa3bSJed Brown       /* count leaves */
28230a96aa3bSJed Brown 
28240a96aa3bSJed Brown       numRoots = pEndC - pStartC;
28250a96aa3bSJed Brown 
28260a96aa3bSJed Brown       numLeaves = 0;
28270a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28280a96aa3bSJed Brown         if (roots[p - pStartF].index >= 0) numLeaves++;
28290a96aa3bSJed Brown       }
28309566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves, &leaves));
28319566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves, &iremote));
28320a96aa3bSJed Brown       numLeaves = 0;
28330a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28340a96aa3bSJed Brown         if (roots[p - pStartF].index >= 0) {
28350a96aa3bSJed Brown           leaves[numLeaves]  = p - pStartF;
28360a96aa3bSJed Brown           iremote[numLeaves] = roots[p - pStartF];
28370a96aa3bSJed Brown           numLeaves++;
28380a96aa3bSJed Brown         }
28390a96aa3bSJed Brown       }
28409566063dSJacob Faibussowitsch       PetscCall(PetscFree(roots));
28419566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, sf));
28420a96aa3bSJed Brown       if (numLeaves == (pEndF - pStartF)) {
28439566063dSJacob Faibussowitsch         PetscCall(PetscFree(leaves));
28449566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf, numRoots, numLeaves, NULL, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
28450a96aa3bSJed Brown       } else {
28469566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf, numRoots, numLeaves, leaves, PETSC_OWN_POINTER, iremote, PETSC_OWN_POINTER));
28470a96aa3bSJed Brown       }
28480a96aa3bSJed Brown     }
28490a96aa3bSJed Brown     if (formCids) {
28500a96aa3bSJed Brown       PetscSF  pointSF;
28510a96aa3bSJed Brown       PetscInt child;
28520a96aa3bSJed Brown 
28539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF, &refTree));
28549566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(plexF, &pointSF));
285557168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, cids, cids, MPI_MAX));
285657168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, cids, cids, MPI_MAX));
28570a96aa3bSJed Brown       if (childIds) *childIds = cids;
285848a46eb9SPierre Jolivet       for (child = 0; child < P4EST_CHILDREN; child++) PetscCall(DMPlexRestoreTransitiveClosure(refTree, child + 1, PETSC_TRUE, NULL, &childClosures[child]));
28599566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(refTree, 0, PETSC_TRUE, NULL, &rootClosure));
28600a96aa3bSJed Brown     }
28610a96aa3bSJed Brown   }
28620a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
28639566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
28640a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
28650a96aa3bSJed Brown     if (!childIds) {
28660a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
28670a96aa3bSJed Brown     } else {
28689566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &pforestC->pointSelfToAdaptCids));
28699566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestC->pointSelfToAdaptCids, cids, pEndF - pStartF));
28700a96aa3bSJed Brown     }
28710a96aa3bSJed Brown   } else if (saveInFine) {
28729566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
28730a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
28740a96aa3bSJed Brown     if (!childIds) {
28750a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
28760a96aa3bSJed Brown     } else {
28779566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &pforestF->pointAdaptToSelfCids));
28789566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestF->pointAdaptToSelfCids, cids, pEndF - pStartF));
28790a96aa3bSJed Brown     }
28800a96aa3bSJed Brown   }
28819566063dSJacob Faibussowitsch   PetscCall(PetscFree2(treeQuads, treeQuadCounts));
28829566063dSJacob Faibussowitsch   PetscCall(PetscFree(coverQuads));
28839566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsC));
28849566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsF));
28859566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeClosureType));
28869566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_free(&sfNodeReduce));
28879566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
28883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
28890a96aa3bSJed Brown }
28900a96aa3bSJed Brown 
28910a96aa3bSJed Brown /* children are sf leaves of parents */
2892d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
2893d71ae5a4SJacob Faibussowitsch {
28940a96aa3bSJed Brown   MPI_Comm           comm;
2895d70f29a3SPierre Jolivet   PetscMPIInt        rank;
28960a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
28970a96aa3bSJed Brown   DM                 plexC, plexF;
28980a96aa3bSJed Brown   PetscInt           pStartC, pEndC, pStartF, pEndF;
28990a96aa3bSJed Brown   PetscSF            pointTransferSF;
29000a96aa3bSJed Brown   PetscBool          allOnes = PETSC_TRUE;
29010a96aa3bSJed Brown 
29020a96aa3bSJed Brown   PetscFunctionBegin;
29030a96aa3bSJed Brown   pforestC = (DM_Forest_pforest *)((DM_Forest *)coarse->data)->data;
29040a96aa3bSJed Brown   pforestF = (DM_Forest_pforest *)((DM_Forest *)fine->data)->data;
290508401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo, PetscObjectComm((PetscObject)coarse), PETSC_ERR_ARG_INCOMP, "DM's must have the same base DM");
29060a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
29079566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm, &rank));
29080a96aa3bSJed Brown 
29090a96aa3bSJed Brown   {
29100a96aa3bSJed Brown     PetscInt i;
29110a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
29120a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
29130a96aa3bSJed Brown         allOnes = PETSC_FALSE;
29140a96aa3bSJed Brown         break;
29150a96aa3bSJed Brown       }
29160a96aa3bSJed Brown     }
29170a96aa3bSJed Brown   }
29189566063dSJacob Faibussowitsch   PetscCall(DMPforestGetTransferSF_Point(coarse, fine, &pointTransferSF, transferIdent, childIds));
29190a96aa3bSJed Brown   if (allOnes) {
29200a96aa3bSJed Brown     *sf = pointTransferSF;
29213ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
29220a96aa3bSJed Brown   }
29230a96aa3bSJed Brown 
29249566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine, &plexF));
29259566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF, &pStartF, &pEndF));
29269566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse, &plexC));
29279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC, &pStartC, &pEndC));
29280a96aa3bSJed Brown   {
29290a96aa3bSJed Brown     PetscInt           numRoots;
29300a96aa3bSJed Brown     PetscInt           numLeaves;
29310a96aa3bSJed Brown     const PetscInt    *leaves;
29320a96aa3bSJed Brown     const PetscSFNode *iremote;
29330a96aa3bSJed Brown     PetscInt           d;
29340a96aa3bSJed Brown     PetscSection       leafSection, rootSection;
29350a96aa3bSJed Brown 
2936217f96c1SStefano Zampini     /* count leaves */
29379566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointTransferSF, &numRoots, &numLeaves, &leaves, &iremote));
29389566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &rootSection));
29399566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF, &leafSection));
29409566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(rootSection, pStartC, pEndC));
29419566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(leafSection, pStartF, pEndF));
29420a96aa3bSJed Brown 
29430a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
29440a96aa3bSJed Brown       PetscInt startC, endC, e;
29450a96aa3bSJed Brown 
29469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC, P4EST_DIM - d, &startC, &endC));
294748a46eb9SPierre Jolivet       for (e = startC; e < endC; e++) PetscCall(PetscSectionSetDof(rootSection, e, dofPerDim[d]));
29480a96aa3bSJed Brown     }
29490a96aa3bSJed Brown 
29500a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
29510a96aa3bSJed Brown       PetscInt startF, endF, e;
29520a96aa3bSJed Brown 
29539566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexF, P4EST_DIM - d, &startF, &endF));
295448a46eb9SPierre Jolivet       for (e = startF; e < endF; e++) PetscCall(PetscSectionSetDof(leafSection, e, dofPerDim[d]));
29550a96aa3bSJed Brown     }
29560a96aa3bSJed Brown 
29579566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(rootSection));
29589566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafSection));
29590a96aa3bSJed Brown     {
29600a96aa3bSJed Brown       PetscInt     nroots, nleaves;
29610a96aa3bSJed Brown       PetscInt    *mine, i, p;
29620a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
29630a96aa3bSJed Brown       PetscSFNode *remote;
29640a96aa3bSJed Brown 
29659566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF - pStartF, &offsets));
29669566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndC - pStartC, &offsetsRoot));
296748a46eb9SPierre Jolivet       for (p = pStartC; p < pEndC; p++) PetscCall(PetscSectionGetOffset(rootSection, p, &offsetsRoot[p - pStartC]));
29689566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointTransferSF, MPIU_INT, offsetsRoot, offsets, MPI_REPLACE));
29699566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointTransferSF, MPIU_INT, offsetsRoot, offsets, MPI_REPLACE));
29709566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(rootSection, &nroots));
29710a96aa3bSJed Brown       nleaves = 0;
29720a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
29730a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
29740a96aa3bSJed Brown         PetscInt dof;
29750a96aa3bSJed Brown 
29769566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection, leaf, &dof));
29770a96aa3bSJed Brown         nleaves += dof;
29780a96aa3bSJed Brown       }
29799566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &mine));
29809566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves, &remote));
29810a96aa3bSJed Brown       nleaves = 0;
29820a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
29830a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
29840a96aa3bSJed Brown         PetscInt dof;
29850a96aa3bSJed Brown         PetscInt off, j;
29860a96aa3bSJed Brown 
29879566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection, leaf, &dof));
29889566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafSection, leaf, &off));
29890a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
29900a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
29910a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
29920a96aa3bSJed Brown           mine[nleaves++]       = off + j;
29930a96aa3bSJed Brown         }
29940a96aa3bSJed Brown       }
29959566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsetsRoot));
29969566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsets));
29979566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm, sf));
29989566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(*sf, nroots, nleaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
29990a96aa3bSJed Brown     }
30009566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
30019566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootSection));
30029566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointTransferSF));
30030a96aa3bSJed Brown   }
30043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30050a96aa3bSJed Brown }
30060a96aa3bSJed Brown 
3007d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA)
3008d71ae5a4SJacob Faibussowitsch {
30090a96aa3bSJed Brown   DM          adaptA, adaptB;
30100a96aa3bSJed Brown   DMAdaptFlag purpose;
30110a96aa3bSJed Brown 
30120a96aa3bSJed Brown   PetscFunctionBegin;
30139566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmA, &adaptA));
30149566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmB, &adaptB));
30150a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
30160a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
30179566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmA, &purpose));
30180a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
30199566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30203ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
30210a96aa3bSJed Brown     }
30220a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
30239566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmB, &purpose));
30240a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
30259566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30263ba16761SJacob Faibussowitsch       PetscFunctionReturn(PETSC_SUCCESS);
30270a96aa3bSJed Brown     }
30280a96aa3bSJed Brown   }
30291baa6e33SBarry Smith   if (sfAtoB) PetscCall(DMPforestGetTransferSF_Internal(dmA, dmB, dofPerDim, sfAtoB, PETSC_TRUE, NULL));
30301baa6e33SBarry Smith   if (sfBtoA) PetscCall(DMPforestGetTransferSF_Internal(dmB, dmA, dofPerDim, sfBtoA, (PetscBool)(sfAtoB == NULL), NULL));
30313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
30320a96aa3bSJed Brown }
30330a96aa3bSJed Brown 
3034d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex)
3035d71ae5a4SJacob Faibussowitsch {
30360a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest *)dm->data;
30370a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)forest->data;
30380a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
30390a96aa3bSJed Brown   PetscInt           cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
30400a96aa3bSJed Brown   PetscInt           pStart, pEnd, pStartBase, pEndBase, p;
30410a96aa3bSJed Brown   DM                 base;
30420a96aa3bSJed Brown   PetscInt          *star      = NULL, starSize;
30430a96aa3bSJed Brown   DMLabelLink        next      = dm->labels;
30440a96aa3bSJed Brown   PetscInt           guess     = 0;
30450a96aa3bSJed Brown   p4est_topidx_t     num_trees = pforest->topo->conn->num_trees;
30460a96aa3bSJed Brown 
30470a96aa3bSJed Brown   PetscFunctionBegin;
30480a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
30490a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
30500a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
30519566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
30520a96aa3bSJed Brown   if (!base) {
30530a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
30540a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
30550a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
30560a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t *)p4est->trees->array;
30570a96aa3bSJed Brown       p4est_topidx_t        t, flt = p4est->first_local_tree;
30580a96aa3bSJed Brown       p4est_topidx_t        llt = pforest->forest->last_local_tree;
30590a96aa3bSJed Brown       DMLabel               ghostLabel;
30600a96aa3bSJed Brown       PetscInt              c;
30610a96aa3bSJed Brown 
30629566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(plex, pforest->ghostName));
30639566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(plex, pforest->ghostName, &ghostLabel));
30640a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
30650a96aa3bSJed Brown         p4est_tree_t     *tree     = &trees[t];
30660a96aa3bSJed Brown         p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
30670a96aa3bSJed Brown         PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
30680a96aa3bSJed Brown         PetscInt          q;
30690a96aa3bSJed Brown 
30700a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
30710a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
30720a96aa3bSJed Brown           PetscInt          f;
30730a96aa3bSJed Brown 
30740a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
30750a96aa3bSJed Brown             p4est_quadrant_t neigh;
30760a96aa3bSJed Brown             int              isOutside;
30770a96aa3bSJed Brown 
3078792fecdfSBarry Smith             PetscCallP4est(p4est_quadrant_face_neighbor, (quad, f, &neigh));
3079792fecdfSBarry Smith             PetscCallP4estReturn(isOutside, p4est_quadrant_is_outside_face, (&neigh));
30800a96aa3bSJed Brown             if (isOutside) {
30810a96aa3bSJed Brown               p4est_topidx_t nt;
30820a96aa3bSJed Brown               PetscInt       nf;
30830a96aa3bSJed Brown 
30840a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
30850a96aa3bSJed Brown               nf = (PetscInt)conn->tree_to_face[t * P4EST_FACES + f];
30860a96aa3bSJed Brown               nf = nf % P4EST_FACES;
30870a96aa3bSJed Brown               if (nt == t && nf == f) {
30880a96aa3bSJed Brown                 PetscInt        plexF = P4estFaceToPetscFace[f];
30890a96aa3bSJed Brown                 const PetscInt *cone;
30900a96aa3bSJed Brown 
30919566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetCone(plex, c, &cone));
30929566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(ghostLabel, cone[plexF], plexF + 1));
30930a96aa3bSJed Brown               }
30940a96aa3bSJed Brown             }
30950a96aa3bSJed Brown           }
30960a96aa3bSJed Brown         }
30970a96aa3bSJed Brown       }
30980a96aa3bSJed Brown     }
30993ba16761SJacob Faibussowitsch     PetscFunctionReturn(PETSC_SUCCESS);
31000a96aa3bSJed Brown   }
31019566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, 0, &cStartBase, &cEndBase));
31029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, 1, &fStartBase, &fEndBase));
31039566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base, P4EST_DIM - 1, &eStartBase, &eEndBase));
31049566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(base, 0, &vStartBase, &vEndBase));
31050a96aa3bSJed Brown 
31069566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 0, &cStart, &cEnd));
31079566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, 1, &fStart, &fEnd));
31089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex, P4EST_DIM - 1, &eStart, &eEnd));
31099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
31100a96aa3bSJed Brown 
31119566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &pStart, &pEnd));
31129566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(base, &pStartBase, &pEndBase));
31130a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
31140a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
31150a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
31160a96aa3bSJed Brown   while (next) {
31170a96aa3bSJed Brown     DMLabel     baseLabel;
31180a96aa3bSJed Brown     DMLabel     label = next->label;
31190a96aa3bSJed Brown     PetscBool   isDepth, isCellType, isGhost, isVTK, isSpmap;
31200a96aa3bSJed Brown     const char *name;
31210a96aa3bSJed Brown 
31229566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)label, &name));
31239566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "depth", &isDepth));
31240a96aa3bSJed Brown     if (isDepth) {
31250a96aa3bSJed Brown       next = next->next;
31260a96aa3bSJed Brown       continue;
31270a96aa3bSJed Brown     }
31289566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "celltype", &isCellType));
31290a96aa3bSJed Brown     if (isCellType) {
31300a96aa3bSJed Brown       next = next->next;
31310a96aa3bSJed Brown       continue;
31320a96aa3bSJed Brown     }
31339566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "ghost", &isGhost));
31340a96aa3bSJed Brown     if (isGhost) {
31350a96aa3bSJed Brown       next = next->next;
31360a96aa3bSJed Brown       continue;
31370a96aa3bSJed Brown     }
31389566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "vtk", &isVTK));
31390a96aa3bSJed Brown     if (isVTK) {
31400a96aa3bSJed Brown       next = next->next;
31410a96aa3bSJed Brown       continue;
31420a96aa3bSJed Brown     }
31439566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name, "_forest_base_subpoint_map", &isSpmap));
31440a96aa3bSJed Brown     if (!isSpmap) {
31459566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(base, name, &baseLabel));
31460a96aa3bSJed Brown       if (!baseLabel) {
31470a96aa3bSJed Brown         next = next->next;
31480a96aa3bSJed Brown         continue;
31490a96aa3bSJed Brown       }
31509566063dSJacob Faibussowitsch       PetscCall(DMLabelCreateIndex(baseLabel, pStartBase, pEndBase));
31510a96aa3bSJed Brown     } else baseLabel = NULL;
31520a96aa3bSJed Brown 
31530a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
31540a96aa3bSJed Brown       PetscInt          s, c = -1, l;
31550a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
31560a96aa3bSJed Brown       p4est_quadrant_t *ghosts  = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
31570a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t *)pforest->forest->trees->array;
31580a96aa3bSJed Brown       p4est_quadrant_t *q;
31590a96aa3bSJed Brown       PetscInt          t, val;
31600a96aa3bSJed Brown       PetscBool         zerosupportpoint = PETSC_FALSE;
31610a96aa3bSJed Brown 
31629566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
31630a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
31640a96aa3bSJed Brown         PetscInt point = star[2 * s];
31650a96aa3bSJed Brown 
31660a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
31679566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(plex, point, PETSC_TRUE, &closureSize, &closure));
31680a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
31690a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
31700a96aa3bSJed Brown             do { /* check parents of q */
31710a96aa3bSJed Brown               q = qParent;
31720a96aa3bSJed Brown               if (q == p) {
31730a96aa3bSJed Brown                 c = point;
31740a96aa3bSJed Brown                 break;
31750a96aa3bSJed Brown               }
31769566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex, q, &qParent, NULL));
31770a96aa3bSJed Brown             } while (qParent != q);
31780a96aa3bSJed Brown             if (c != -1) break;
31799566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(plex, pp, &pParent, NULL));
31800a96aa3bSJed Brown             q = closure[2 * l];
31810a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
31820a96aa3bSJed Brown               pp = pParent;
31830a96aa3bSJed Brown               if (pp == q) {
31840a96aa3bSJed Brown                 c = point;
31850a96aa3bSJed Brown                 break;
31860a96aa3bSJed Brown               }
31879566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex, pp, &pParent, NULL));
31880a96aa3bSJed Brown             }
31890a96aa3bSJed Brown             if (c != -1) break;
31900a96aa3bSJed Brown           }
31919566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(plex, point, PETSC_TRUE, NULL, &closure));
31920a96aa3bSJed Brown           if (l < closureSize) break;
31930a96aa3bSJed Brown         } else {
31940a96aa3bSJed Brown           PetscInt supportSize;
31950a96aa3bSJed Brown 
31969566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(plex, point, &supportSize));
31970a96aa3bSJed Brown           zerosupportpoint = (PetscBool)(zerosupportpoint || !supportSize);
31980a96aa3bSJed Brown         }
31990a96aa3bSJed Brown       }
32000a96aa3bSJed Brown       if (c < 0) {
32010a96aa3bSJed Brown         const char *prefix;
32020a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
32030a96aa3bSJed Brown 
32049566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm, &prefix));
32059566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options, prefix, "-dm_forest_print_label_error", &print, NULL));
32060a96aa3bSJed Brown         if (print) {
32070a96aa3bSJed Brown           PetscInt i;
32080a96aa3bSJed Brown 
320963a3b9bcSJacob 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));
321063a3b9bcSJacob 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]));
32110a96aa3bSJed Brown         }
32129566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, NULL, &star));
32130a96aa3bSJed Brown         if (zerosupportpoint) continue;
32149371c9d4SSatish Balay         else
32159371c9d4SSatish 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");
32160a96aa3bSJed Brown       }
32179566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, NULL, &star));
32180a96aa3bSJed Brown 
32190a96aa3bSJed Brown       if (c < cLocalStart) {
32200a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
3221*f4f49eeaSPierre Jolivet         q = &ghosts[c];
32220a96aa3bSJed Brown         t = (PetscInt)q->p.which_tree;
32230a96aa3bSJed Brown       } else if (c < cLocalEnd) {
32240a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
32250a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
32260a96aa3bSJed Brown 
32270a96aa3bSJed Brown         c -= cLocalStart;
32280a96aa3bSJed Brown 
32290a96aa3bSJed Brown         do {
32300a96aa3bSJed Brown           p4est_tree_t *tree;
32310a96aa3bSJed Brown 
32321dca8a05SBarry Smith           PetscCheck(guess >= lo && guess < num_trees && lo < hi, PETSC_COMM_SELF, PETSC_ERR_PLIB, "failed binary search");
32330a96aa3bSJed Brown           tree = &trees[guess];
32340a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
32350a96aa3bSJed Brown             hi = guess;
32360a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt)tree->quadrants.elem_count) {
32370a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt)tree->quadrants_offset];
32380a96aa3bSJed Brown             t = guess;
32390a96aa3bSJed Brown             break;
32400a96aa3bSJed Brown           } else {
32410a96aa3bSJed Brown             lo = guess + 1;
32420a96aa3bSJed Brown           }
32430a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
32440a96aa3bSJed Brown         } while (1);
32450a96aa3bSJed Brown       } else {
32460a96aa3bSJed Brown         /* get from the end of the ghost layer */
32470a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
32480a96aa3bSJed Brown 
3249*f4f49eeaSPierre Jolivet         q = &ghosts[c];
32500a96aa3bSJed Brown         t = (PetscInt)q->p.which_tree;
32510a96aa3bSJed Brown       }
32520a96aa3bSJed Brown 
32530a96aa3bSJed Brown       if (l == 0) { /* cell */
32540a96aa3bSJed Brown         if (baseLabel) {
32559566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32560a96aa3bSJed Brown         } else {
32570a96aa3bSJed Brown           val = t + cStartBase;
32580a96aa3bSJed Brown         }
32599566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label, p, val));
32600a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
32610a96aa3bSJed Brown         p4est_quadrant_t nq;
32620a96aa3bSJed Brown         int              isInside;
32630a96aa3bSJed Brown 
32640a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
3265792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_face_neighbor, (q, l, &nq));
3266792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
32670a96aa3bSJed Brown         if (isInside) {
32680a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
32690a96aa3bSJed Brown           if (baseLabel) {
32709566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32710a96aa3bSJed Brown           } else {
32720a96aa3bSJed Brown             val = t + cStartBase;
32730a96aa3bSJed Brown           }
32749566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32750a96aa3bSJed Brown         } else {
32760a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
32770a96aa3bSJed Brown 
32780a96aa3bSJed Brown           if (baseLabel) {
32799566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
32800a96aa3bSJed Brown           } else {
32810a96aa3bSJed Brown             val = f + fStartBase;
32820a96aa3bSJed Brown           }
32839566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
32840a96aa3bSJed Brown         }
32850a96aa3bSJed Brown   #if defined(P4_TO_P8)
32860a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
32870a96aa3bSJed Brown         p4est_quadrant_t nq;
32880a96aa3bSJed Brown         int              isInside;
32890a96aa3bSJed Brown 
32900a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
3291792fecdfSBarry Smith         PetscCallP4est(p8est_quadrant_edge_neighbor, (q, l, &nq));
3292792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
32930a96aa3bSJed Brown         if (isInside) {
32940a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
32950a96aa3bSJed Brown           if (baseLabel) {
32969566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
32970a96aa3bSJed Brown           } else {
32980a96aa3bSJed Brown             val = t + cStartBase;
32990a96aa3bSJed Brown           }
33009566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
33010a96aa3bSJed Brown         } else {
33020a96aa3bSJed Brown           int isOutsideFace;
33030a96aa3bSJed Brown 
3304792fecdfSBarry Smith           PetscCallP4estReturn(isOutsideFace, p4est_quadrant_is_outside_face, (&nq));
33050a96aa3bSJed Brown           if (isOutsideFace) {
33060a96aa3bSJed Brown             PetscInt f;
33070a96aa3bSJed Brown 
33080a96aa3bSJed Brown             if (nq.x < 0) {
33090a96aa3bSJed Brown               f = 0;
33100a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33110a96aa3bSJed Brown               f = 1;
33120a96aa3bSJed Brown             } else if (nq.y < 0) {
33130a96aa3bSJed Brown               f = 2;
33140a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33150a96aa3bSJed Brown               f = 3;
33160a96aa3bSJed Brown             } else if (nq.z < 0) {
33170a96aa3bSJed Brown               f = 4;
33180a96aa3bSJed Brown             } else {
33190a96aa3bSJed Brown               f = 5;
33200a96aa3bSJed Brown             }
33210a96aa3bSJed Brown             f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33220a96aa3bSJed Brown             if (baseLabel) {
33239566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
33240a96aa3bSJed Brown             } else {
33250a96aa3bSJed Brown               val = f + fStartBase;
33260a96aa3bSJed Brown             }
33279566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33280a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
33290a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
33300a96aa3bSJed Brown 
33310a96aa3bSJed Brown             if (baseLabel) {
33329566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, e + eStartBase, &val));
33330a96aa3bSJed Brown             } else {
33340a96aa3bSJed Brown               val = e + eStartBase;
33350a96aa3bSJed Brown             }
33369566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33370a96aa3bSJed Brown           }
33380a96aa3bSJed Brown         }
33390a96aa3bSJed Brown   #endif
33400a96aa3bSJed Brown       } else { /* vertex */
33410a96aa3bSJed Brown         p4est_quadrant_t nq;
33420a96aa3bSJed Brown         int              isInside;
33430a96aa3bSJed Brown 
33440a96aa3bSJed Brown   #if defined(P4_TO_P8)
33450a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
33460a96aa3bSJed Brown   #else
33470a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
33480a96aa3bSJed Brown   #endif
3349792fecdfSBarry Smith         PetscCallP4est(p4est_quadrant_corner_neighbor, (q, l, &nq));
3350792fecdfSBarry Smith         PetscCallP4estReturn(isInside, p4est_quadrant_is_inside_root, (&nq));
33510a96aa3bSJed Brown         if (isInside) {
33520a96aa3bSJed Brown           if (baseLabel) {
33539566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel, t + cStartBase, &val));
33540a96aa3bSJed Brown           } else {
33550a96aa3bSJed Brown             val = t + cStartBase;
33560a96aa3bSJed Brown           }
33579566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label, p, val));
33580a96aa3bSJed Brown         } else {
33590a96aa3bSJed Brown           int isOutside;
33600a96aa3bSJed Brown 
3361792fecdfSBarry Smith           PetscCallP4estReturn(isOutside, p4est_quadrant_is_outside_face, (&nq));
33620a96aa3bSJed Brown           if (isOutside) {
33630a96aa3bSJed Brown             PetscInt f = -1;
33640a96aa3bSJed Brown 
33650a96aa3bSJed Brown             if (nq.x < 0) {
33660a96aa3bSJed Brown               f = 0;
33670a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33680a96aa3bSJed Brown               f = 1;
33690a96aa3bSJed Brown             } else if (nq.y < 0) {
33700a96aa3bSJed Brown               f = 2;
33710a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33720a96aa3bSJed Brown               f = 3;
33730a96aa3bSJed Brown   #if defined(P4_TO_P8)
33740a96aa3bSJed Brown             } else if (nq.z < 0) {
33750a96aa3bSJed Brown               f = 4;
33760a96aa3bSJed Brown             } else {
33770a96aa3bSJed Brown               f = 5;
33780a96aa3bSJed Brown   #endif
33790a96aa3bSJed Brown             }
33800a96aa3bSJed Brown             f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33810a96aa3bSJed Brown             if (baseLabel) {
33829566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, f + fStartBase, &val));
33830a96aa3bSJed Brown             } else {
33840a96aa3bSJed Brown               val = f + fStartBase;
33850a96aa3bSJed Brown             }
33869566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
33870a96aa3bSJed Brown             continue;
33880a96aa3bSJed Brown           }
33890a96aa3bSJed Brown   #if defined(P4_TO_P8)
3390792fecdfSBarry Smith           PetscCallP4estReturn(isOutside, p8est_quadrant_is_outside_edge, (&nq));
33910a96aa3bSJed Brown           if (isOutside) {
33920a96aa3bSJed Brown             /* outside edge */
33930a96aa3bSJed Brown             PetscInt e = -1;
33940a96aa3bSJed Brown 
33950a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
33960a96aa3bSJed Brown               if (nq.z < 0) {
33970a96aa3bSJed Brown                 if (nq.y < 0) {
33980a96aa3bSJed Brown                   e = 0;
33990a96aa3bSJed Brown                 } else {
34000a96aa3bSJed Brown                   e = 1;
34010a96aa3bSJed Brown                 }
34020a96aa3bSJed Brown               } else {
34030a96aa3bSJed Brown                 if (nq.y < 0) {
34040a96aa3bSJed Brown                   e = 2;
34050a96aa3bSJed Brown                 } else {
34060a96aa3bSJed Brown                   e = 3;
34070a96aa3bSJed Brown                 }
34080a96aa3bSJed Brown               }
34090a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
34100a96aa3bSJed Brown               if (nq.z < 0) {
34110a96aa3bSJed Brown                 if (nq.x < 0) {
34120a96aa3bSJed Brown                   e = 4;
34130a96aa3bSJed Brown                 } else {
34140a96aa3bSJed Brown                   e = 5;
34150a96aa3bSJed Brown                 }
34160a96aa3bSJed Brown               } else {
34170a96aa3bSJed Brown                 if (nq.x < 0) {
34180a96aa3bSJed Brown                   e = 6;
34190a96aa3bSJed Brown                 } else {
34200a96aa3bSJed Brown                   e = 7;
34210a96aa3bSJed Brown                 }
34220a96aa3bSJed Brown               }
34230a96aa3bSJed Brown             } else {
34240a96aa3bSJed Brown               if (nq.y < 0) {
34250a96aa3bSJed Brown                 if (nq.x < 0) {
34260a96aa3bSJed Brown                   e = 8;
34270a96aa3bSJed Brown                 } else {
34280a96aa3bSJed Brown                   e = 9;
34290a96aa3bSJed Brown                 }
34300a96aa3bSJed Brown               } else {
34310a96aa3bSJed Brown                 if (nq.x < 0) {
34320a96aa3bSJed Brown                   e = 10;
34330a96aa3bSJed Brown                 } else {
34340a96aa3bSJed Brown                   e = 11;
34350a96aa3bSJed Brown                 }
34360a96aa3bSJed Brown               }
34370a96aa3bSJed Brown             }
34380a96aa3bSJed Brown 
34390a96aa3bSJed Brown             e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
34400a96aa3bSJed Brown             if (baseLabel) {
34419566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, e + eStartBase, &val));
34420a96aa3bSJed Brown             } else {
34430a96aa3bSJed Brown               val = e + eStartBase;
34440a96aa3bSJed Brown             }
34459566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
34460a96aa3bSJed Brown             continue;
34470a96aa3bSJed Brown           }
34480a96aa3bSJed Brown   #endif
34490a96aa3bSJed Brown           {
34500a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
34510a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
34520a96aa3bSJed Brown 
34530a96aa3bSJed Brown             if (baseLabel) {
34549566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel, v + vStartBase, &val));
34550a96aa3bSJed Brown             } else {
34560a96aa3bSJed Brown               val = v + vStartBase;
34570a96aa3bSJed Brown             }
34589566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label, p, val));
34590a96aa3bSJed Brown           }
34600a96aa3bSJed Brown         }
34610a96aa3bSJed Brown       }
34620a96aa3bSJed Brown     }
34630a96aa3bSJed Brown     next = next->next;
34640a96aa3bSJed Brown   }
34653ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
34660a96aa3bSJed Brown }
34670a96aa3bSJed Brown 
3468d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex)
3469d71ae5a4SJacob Faibussowitsch {
34700a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
34710a96aa3bSJed Brown   DM                 adapt;
34720a96aa3bSJed Brown 
34730a96aa3bSJed Brown   PetscFunctionBegin;
34743ba16761SJacob Faibussowitsch   if (pforest->labelsFinalized) PetscFunctionReturn(PETSC_SUCCESS);
34750a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
34769566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm, &adapt));
34770a96aa3bSJed Brown   if (!adapt) {
34780a96aa3bSJed Brown     /* Initialize labels from the base dm */
34799566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsInitialize(dm, plex));
34800a96aa3bSJed Brown   } else {
34810a96aa3bSJed Brown     PetscInt    dofPerDim[4] = {1, 1, 1, 1};
34820a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
34830a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
34840a96aa3bSJed Brown     PetscInt   *values, *adaptValues;
34850a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
34860a96aa3bSJed Brown     DMLabel     adaptLabel;
34870a96aa3bSJed Brown     DM          adaptPlex;
34880a96aa3bSJed Brown 
34899566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm, &adaptLabel));
34909566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(adapt, &adaptPlex));
34919566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF(adapt, dm, dofPerDim, &transferForward, &transferBackward));
34929566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &pStart, &pEnd));
34939566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(adaptPlex, &pStartA, &pEndA));
34949566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEnd - pStart, &values, pEndA - pStartA, &adaptValues));
34959566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex, &pointSF));
34960a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
34970a96aa3bSJed Brown       PetscInt p;
34980a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p - pStartA] = -1;
34990a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p - pStart] = -2;
35000a96aa3bSJed Brown       if (transferForward) {
35019566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
35029566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
35030a96aa3bSJed Brown       }
35040a96aa3bSJed Brown       if (transferBackward) {
350557168dbeSPierre Jolivet         PetscCall(PetscSFReduceBegin(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
350657168dbeSPierre Jolivet         PetscCall(PetscSFReduceEnd(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35070a96aa3bSJed Brown       }
35080a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35090a96aa3bSJed Brown         PetscInt q = p, parent;
35100a96aa3bSJed Brown 
35119566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35120a96aa3bSJed Brown         while (parent != q) {
35130a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
35140a96aa3bSJed Brown           q = parent;
35159566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35160a96aa3bSJed Brown         }
35170a96aa3bSJed Brown       }
351857168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, values, values, MPI_MAX));
351957168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, values, values, MPI_MAX));
35209566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35219566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, values, values, MPI_REPLACE));
3522ad540459SPierre Jolivet       for (p = pStart; p < pEnd; p++) PetscCheck(values[p - pStart] != -2, PETSC_COMM_SELF, PETSC_ERR_PLIB, "uncovered point %" PetscInt_FMT, p);
35230a96aa3bSJed Brown     }
35240a96aa3bSJed Brown     while (next) {
35250a96aa3bSJed Brown       DMLabel     nextLabel = next->label;
35260a96aa3bSJed Brown       const char *name;
35270a96aa3bSJed Brown       PetscBool   isDepth, isCellType, isGhost, isVTK;
35280a96aa3bSJed Brown       DMLabel     label;
35290a96aa3bSJed Brown       PetscInt    p;
35300a96aa3bSJed Brown 
35319566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject)nextLabel, &name));
35329566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "depth", &isDepth));
35330a96aa3bSJed Brown       if (isDepth) {
35340a96aa3bSJed Brown         next = next->next;
35350a96aa3bSJed Brown         continue;
35360a96aa3bSJed Brown       }
35379566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "celltype", &isCellType));
35380a96aa3bSJed Brown       if (isCellType) {
35390a96aa3bSJed Brown         next = next->next;
35400a96aa3bSJed Brown         continue;
35410a96aa3bSJed Brown       }
35429566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "ghost", &isGhost));
35430a96aa3bSJed Brown       if (isGhost) {
35440a96aa3bSJed Brown         next = next->next;
35450a96aa3bSJed Brown         continue;
35460a96aa3bSJed Brown       }
35479566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name, "vtk", &isVTK));
35480a96aa3bSJed Brown       if (isVTK) {
35490a96aa3bSJed Brown         next = next->next;
35500a96aa3bSJed Brown         continue;
35510a96aa3bSJed Brown       }
35520a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
35530a96aa3bSJed Brown         next = next->next;
35540a96aa3bSJed Brown         continue;
35550a96aa3bSJed Brown       }
35560a96aa3bSJed Brown       /* label was created earlier */
35579566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm, name, &label));
355848a46eb9SPierre Jolivet       for (p = pStartA; p < pEndA; p++) PetscCall(DMLabelGetValue(nextLabel, p, &adaptValues[p]));
35590a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
35600a96aa3bSJed Brown 
35611baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastBegin(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
356257168dbeSPierre Jolivet       if (transferBackward) PetscCall(PetscSFReduceBegin(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35631baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastEnd(transferForward, MPIU_INT, adaptValues, values, MPI_REPLACE));
356457168dbeSPierre Jolivet       if (transferBackward) PetscCall(PetscSFReduceEnd(transferBackward, MPIU_INT, adaptValues, values, MPI_MAX));
35650a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35660a96aa3bSJed Brown         PetscInt q = p, parent;
35670a96aa3bSJed Brown 
35689566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35690a96aa3bSJed Brown         while (parent != q) {
35700a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
35710a96aa3bSJed Brown           q = parent;
35729566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex, q, &parent, NULL));
35730a96aa3bSJed Brown         }
35740a96aa3bSJed Brown       }
357557168dbeSPierre Jolivet       PetscCall(PetscSFReduceBegin(pointSF, MPIU_INT, values, values, MPI_MAX));
357657168dbeSPierre Jolivet       PetscCall(PetscSFReduceEnd(pointSF, MPIU_INT, values, values, MPI_MAX));
35779566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35789566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF, MPIU_INT, values, values, MPI_REPLACE));
35790a96aa3bSJed Brown 
358048a46eb9SPierre Jolivet       for (p = pStart; p < pEnd; p++) PetscCall(DMLabelSetValue(label, p, values[p]));
35810a96aa3bSJed Brown       next = next->next;
35820a96aa3bSJed Brown     }
35839566063dSJacob Faibussowitsch     PetscCall(PetscFree2(values, adaptValues));
35849566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferForward));
35859566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferBackward));
35860a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
35870a96aa3bSJed Brown   }
35883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
35890a96aa3bSJed Brown }
35900a96aa3bSJed Brown 
3591d71ae5a4SJacob 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)
3592d71ae5a4SJacob Faibussowitsch {
35930a96aa3bSJed Brown   PetscInt     closureSize, c, coordStart, coordEnd, coordDim;
35940a96aa3bSJed Brown   PetscInt    *closure = NULL;
35950a96aa3bSJed Brown   PetscSection coordSec;
35960a96aa3bSJed Brown 
35970a96aa3bSJed Brown   PetscFunctionBegin;
35989566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &coordSec));
35999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSec, &coordStart, &coordEnd));
36009566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(plex, &coordDim));
36019566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(plex, cell, PETSC_TRUE, &closureSize, &closure));
36020a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
36030a96aa3bSJed Brown     PetscInt point = closure[2 * c];
36040a96aa3bSJed Brown 
36050a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
36060a96aa3bSJed Brown       PetscInt dof, off;
36070a96aa3bSJed Brown       PetscInt nCoords, i;
36089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec, point, &dof));
360908401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not understand coordinate layout");
36100a96aa3bSJed Brown       nCoords = dof / coordDim;
36119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec, point, &off));
36120a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
36130a96aa3bSJed Brown         PetscScalar *coord               = &coords[off + i * coordDim];
36140a96aa3bSJed Brown         double       coordP4est[3]       = {0.};
36150a96aa3bSJed Brown         double       coordP4estMapped[3] = {0.};
36160a96aa3bSJed Brown         PetscInt     j;
36170a96aa3bSJed Brown         PetscReal    treeCoords[P4EST_CHILDREN][3] = {{0.}};
36180a96aa3bSJed Brown         PetscReal    eta[3]                        = {0.};
36190a96aa3bSJed Brown         PetscInt     numRounds                     = 10;
36200a96aa3bSJed Brown         PetscReal    coordGuess[3]                 = {0.};
36210a96aa3bSJed Brown 
36220a96aa3bSJed Brown         eta[0] = (PetscReal)q->x / (PetscReal)P4EST_ROOT_LEN;
36230a96aa3bSJed Brown         eta[1] = (PetscReal)q->y / (PetscReal)P4EST_ROOT_LEN;
36240a96aa3bSJed Brown   #if defined(P4_TO_P8)
36250a96aa3bSJed Brown         eta[2] = (PetscReal)q->z / (PetscReal)P4EST_ROOT_LEN;
36260a96aa3bSJed Brown   #endif
36270a96aa3bSJed Brown 
36280a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
36290a96aa3bSJed Brown           PetscInt k;
36300a96aa3bSJed Brown 
36310a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
36320a96aa3bSJed Brown         }
36330a96aa3bSJed Brown 
36340a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
36350a96aa3bSJed Brown           PetscInt  k;
36360a96aa3bSJed Brown           PetscReal prod = 1.;
36370a96aa3bSJed Brown 
36380a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
36390a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
36400a96aa3bSJed Brown         }
36410a96aa3bSJed Brown 
36420a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
36430a96aa3bSJed Brown           PetscInt dir;
36440a96aa3bSJed Brown 
36450a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
36460a96aa3bSJed Brown             PetscInt  k;
36470a96aa3bSJed Brown             PetscReal diff[3];
36480a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
36490a96aa3bSJed Brown             PetscReal rhs, scale, update;
36500a96aa3bSJed Brown 
36510a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
36520a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
36530a96aa3bSJed Brown               PetscInt  l;
36540a96aa3bSJed Brown               PetscReal prod = 1.;
36550a96aa3bSJed Brown 
36560a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
36570a96aa3bSJed Brown                 if (l == dir) {
36580a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? 1. : -1.;
36590a96aa3bSJed Brown                 } else {
36600a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
36610a96aa3bSJed Brown                 }
36620a96aa3bSJed Brown               }
36630a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
36640a96aa3bSJed Brown             }
36650a96aa3bSJed Brown             rhs   = 0.;
36660a96aa3bSJed Brown             scale = 0;
36670a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
36680a96aa3bSJed Brown               rhs += diff[k] * dXdeta[k];
36690a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
36700a96aa3bSJed Brown             }
36710a96aa3bSJed Brown             update = rhs / scale;
36720a96aa3bSJed Brown             eta[dir] += update;
36730a96aa3bSJed Brown             eta[dir] = PetscMin(eta[dir], 1.);
36740a96aa3bSJed Brown             eta[dir] = PetscMax(eta[dir], 0.);
36750a96aa3bSJed Brown 
36760a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
36770a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
36780a96aa3bSJed Brown               PetscInt  l;
36790a96aa3bSJed Brown               PetscReal prod = 1.;
36800a96aa3bSJed Brown 
36810a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
36820a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
36830a96aa3bSJed Brown             }
36840a96aa3bSJed Brown           }
36850a96aa3bSJed Brown         }
36860a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double)eta[j];
36870a96aa3bSJed Brown 
36880a96aa3bSJed Brown         if (geom) {
36890a96aa3bSJed Brown           (geom->X)(geom, t, coordP4est, coordP4estMapped);
36900a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar)coordP4estMapped[j];
36910a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF, PETSC_ERR_SUP, "Not coded");
36920a96aa3bSJed Brown       }
36930a96aa3bSJed Brown     }
36940a96aa3bSJed Brown   }
36959566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(plex, cell, PETSC_TRUE, &closureSize, &closure));
36963ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
36970a96aa3bSJed Brown }
36980a96aa3bSJed Brown 
3699d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex)
3700d71ae5a4SJacob Faibussowitsch {
37010a96aa3bSJed Brown   DM_Forest         *forest;
37020a96aa3bSJed Brown   DM_Forest_pforest *pforest;
37030a96aa3bSJed Brown   p4est_geometry_t  *geom;
37040a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd;
37050a96aa3bSJed Brown   Vec                coordLocalVec;
37060a96aa3bSJed Brown   PetscScalar       *coords;
37070a96aa3bSJed Brown   p4est_topidx_t     flt, llt, t;
37080a96aa3bSJed Brown   p4est_tree_t      *trees;
37090a96aa3bSJed Brown   PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void *);
37100a96aa3bSJed Brown   void *mapCtx;
37110a96aa3bSJed Brown 
37120a96aa3bSJed Brown   PetscFunctionBegin;
37130a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
37140a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
37150a96aa3bSJed Brown   geom    = pforest->topo->geom;
37169566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseCoordinateMapping(dm, &map, &mapCtx));
37173ba16761SJacob Faibussowitsch   if (!geom && !map) PetscFunctionReturn(PETSC_SUCCESS);
37189566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex, &coordLocalVec));
37199566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordLocalVec, &coords));
37200a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
37210a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
37220a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
37230a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
37240a96aa3bSJed Brown   trees       = (p4est_tree_t *)pforest->forest->trees->array;
37250a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
37260a96aa3bSJed Brown     PetscSection coordSec;
37270a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
37280a96aa3bSJed Brown     DM           base;
37290a96aa3bSJed Brown 
37309566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
37312827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
37320a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
37339566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm, &base));
37349566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(plex, &coordSec));
37359566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(coordSec, &coordStart, &coordEnd));
37369566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(plex, &coordDim));
37370a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim, 3);
37380a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
37390a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
37400a96aa3bSJed Brown       PetscInt  dof, off, cell = -1, coarsePoint = -1;
37410a96aa3bSJed Brown       PetscInt  nCoords, i;
37429566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec, p, &dof));
374308401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Did not understand coordinate layout");
37440a96aa3bSJed Brown       nCoords = dof / coordDim;
37459566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec, p, &off));
37469566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
37470a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
37480a96aa3bSJed Brown         PetscInt point = star[2 * i];
37490a96aa3bSJed Brown 
37500a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
37510a96aa3bSJed Brown           cell = point;
37520a96aa3bSJed Brown           break;
37530a96aa3bSJed Brown         }
37540a96aa3bSJed Brown       }
37559566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex, p, PETSC_FALSE, &starSize, &star));
37560a96aa3bSJed Brown       if (cell >= 0) {
37570a96aa3bSJed Brown         if (cell < cLocalStart) {
37580a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37590a96aa3bSJed Brown 
37600a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
37610a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
37620a96aa3bSJed Brown           cell -= cLocalStart;
37630a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
3764*f4f49eeaSPierre Jolivet             p4est_tree_t *tree = &trees[t];
37650a96aa3bSJed Brown 
37660a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t)cell < tree->quadrants_offset + tree->quadrants.elem_count) {
37670a96aa3bSJed Brown               coarsePoint = t;
37680a96aa3bSJed Brown               break;
37690a96aa3bSJed Brown             }
37700a96aa3bSJed Brown           }
37710a96aa3bSJed Brown         } else {
37720a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37730a96aa3bSJed Brown 
37740a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
37750a96aa3bSJed Brown         }
37760a96aa3bSJed Brown       }
37770a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
37780a96aa3bSJed Brown         PetscScalar *coord               = &coords[off + i * coordDim];
37790a96aa3bSJed Brown         PetscReal    coordP4est[3]       = {0.};
37800a96aa3bSJed Brown         PetscReal    coordP4estMapped[3] = {0.};
37810a96aa3bSJed Brown         PetscInt     j;
37820a96aa3bSJed Brown 
37830a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
37849566063dSJacob Faibussowitsch         PetscCall((map)(base, coarsePoint, p4estCoordDim, coordP4est, coordP4estMapped, mapCtx));
37850a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar)coordP4estMapped[j];
37860a96aa3bSJed Brown       }
37870a96aa3bSJed Brown     }
37880a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
37890a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
37900a96aa3bSJed Brown 
37919566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
37922827ebadSStefano Zampini     PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
37930a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
37940a96aa3bSJed Brown     if (cLocalStart > 0) {
37950a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
37960a96aa3bSJed Brown       PetscInt          count;
37970a96aa3bSJed Brown 
37980a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
37990a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
38000a96aa3bSJed Brown         p4est_topidx_t    t    = quad->p.which_tree;
38010a96aa3bSJed Brown 
38029566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count, quad, t, pforest->topo->conn, coords));
38030a96aa3bSJed Brown       }
38040a96aa3bSJed Brown     }
38050a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
3806*f4f49eeaSPierre Jolivet       p4est_tree_t     *tree     = &trees[t];
38070a96aa3bSJed Brown       PetscInt          offset   = cLocalStart + tree->quadrants_offset, i;
38080a96aa3bSJed Brown       PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
38090a96aa3bSJed Brown       p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
38100a96aa3bSJed Brown 
38110a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
38120a96aa3bSJed Brown         PetscInt count = i + offset;
38130a96aa3bSJed Brown 
38149566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count, &quads[i], t, pforest->topo->conn, coords));
38150a96aa3bSJed Brown       }
38160a96aa3bSJed Brown     }
38170a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
38180a96aa3bSJed Brown       p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
38190a96aa3bSJed Brown       PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
38200a96aa3bSJed Brown       PetscInt          count;
38210a96aa3bSJed Brown 
38220a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
38230a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
38240a96aa3bSJed Brown         p4est_topidx_t    t    = quad->p.which_tree;
38250a96aa3bSJed Brown 
38269566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex, geom, count + cLocalEnd, quad, t, pforest->topo->conn, coords));
38270a96aa3bSJed Brown       }
38280a96aa3bSJed Brown     }
38290a96aa3bSJed Brown   }
38309566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordLocalVec, &coords));
38313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
38320a96aa3bSJed Brown }
38330a96aa3bSJed Brown 
3834d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestQuadrantIsInterior(p4est_quadrant_t *quad, PetscBool *is_interior)
3835d71ae5a4SJacob Faibussowitsch {
3836852b71a7SToby Isaac   PetscFunctionBegin;
3837852b71a7SToby Isaac   p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3838852b71a7SToby Isaac   if ((quad->x > 0) && (quad->x + h < P4EST_ROOT_LEN)
3839852b71a7SToby Isaac   #ifdef P4_TO_P8
3840852b71a7SToby Isaac       && (quad->z > 0) && (quad->z + h < P4EST_ROOT_LEN)
3841852b71a7SToby Isaac   #endif
3842852b71a7SToby Isaac       && (quad->y > 0) && (quad->y + h < P4EST_ROOT_LEN)) {
3843852b71a7SToby Isaac     *is_interior = PETSC_TRUE;
3844852b71a7SToby Isaac   } else {
3845852b71a7SToby Isaac     *is_interior = PETSC_FALSE;
3846852b71a7SToby Isaac   }
38473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3848852b71a7SToby Isaac }
3849852b71a7SToby Isaac 
3850852b71a7SToby Isaac /* We always use DG coordinates with p4est: if they do not match the vertex
3851852b71a7SToby Isaac    coordinates, add space for them in the section */
3852d71ae5a4SJacob 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)
3853d71ae5a4SJacob Faibussowitsch {
3854852b71a7SToby Isaac   PetscBool is_interior;
3855852b71a7SToby Isaac 
3856852b71a7SToby Isaac   PetscFunctionBegin;
3857852b71a7SToby Isaac   PetscCall(PforestQuadrantIsInterior(quad, &is_interior));
3858852b71a7SToby Isaac   if (is_interior) { // quads in the interior of a coarse cell can't touch periodic interfaces
3859852b71a7SToby Isaac     PetscCall(PetscSectionSetDof(newSection, cell, 0));
3860852b71a7SToby Isaac     PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3861852b71a7SToby Isaac   } else {
3862852b71a7SToby Isaac     PetscInt     cSize;
3863852b71a7SToby Isaac     PetscScalar *values      = NULL;
3864852b71a7SToby Isaac     PetscBool    same_coords = PETSC_TRUE;
3865852b71a7SToby Isaac 
3866852b71a7SToby Isaac     PetscCall(DMPlexVecGetClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3867852b71a7SToby Isaac     PetscAssert(cSize == cDim * P4EST_CHILDREN, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected closure size");
3868852b71a7SToby Isaac     for (int c = 0; c < P4EST_CHILDREN; c++) {
3869852b71a7SToby Isaac       p4est_qcoord_t quad_coords[3];
3870852b71a7SToby Isaac       p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3871852b71a7SToby Isaac       double         corner_coords[3];
3872852b71a7SToby Isaac       double         vert_coords[3];
3873852b71a7SToby Isaac       PetscInt       corner = PetscVertToP4estVert[c];
3874852b71a7SToby Isaac 
3875ad540459SPierre Jolivet       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) vert_coords[d] = PetscRealPart(values[c * cDim + d]);
3876852b71a7SToby Isaac 
3877852b71a7SToby Isaac       quad_coords[0] = quad->x;
3878852b71a7SToby Isaac       quad_coords[1] = quad->y;
3879852b71a7SToby Isaac   #ifdef P4_TO_P8
3880852b71a7SToby Isaac       quad_coords[2] = quad->z;
3881852b71a7SToby Isaac   #endif
3882ad540459SPierre Jolivet       for (int d = 0; d < 3; d++) quad_coords[d] += (corner & (1 << d)) ? h : 0;
3883852b71a7SToby Isaac   #ifndef P4_TO_P8
3884648bc8c4SBarry Smith       PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3885852b71a7SToby Isaac   #else
3886648bc8c4SBarry Smith       PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3887852b71a7SToby Isaac   #endif
3888852b71a7SToby Isaac       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
3889852b71a7SToby Isaac         if (fabs(vert_coords[d] - corner_coords[d]) > PETSC_SMALL) {
3890852b71a7SToby Isaac           same_coords = PETSC_FALSE;
3891852b71a7SToby Isaac           break;
3892852b71a7SToby Isaac         }
3893852b71a7SToby Isaac       }
3894852b71a7SToby Isaac     }
3895852b71a7SToby Isaac     if (same_coords) {
3896852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, 0));
3897852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3898852b71a7SToby Isaac     } else {
3899852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, cSize));
3900852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, cSize));
3901852b71a7SToby Isaac     }
3902852b71a7SToby Isaac     PetscCall(DMPlexVecRestoreClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3903852b71a7SToby Isaac   }
39043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3905852b71a7SToby Isaac }
3906852b71a7SToby Isaac 
3907d71ae5a4SJacob Faibussowitsch static PetscErrorCode PforestLocalizeCell(DM plex, PetscInt cDim, DM_Forest_pforest *pforest, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad, PetscScalar coords[])
3908d71ae5a4SJacob Faibussowitsch {
3909852b71a7SToby Isaac   PetscInt cdof, off;
3910852b71a7SToby Isaac 
3911852b71a7SToby Isaac   PetscFunctionBegin;
3912852b71a7SToby Isaac   PetscCall(PetscSectionGetDof(newSection, cell, &cdof));
39133ba16761SJacob Faibussowitsch   if (!cdof) PetscFunctionReturn(PETSC_SUCCESS);
3914852b71a7SToby Isaac 
3915852b71a7SToby Isaac   PetscCall(PetscSectionGetOffset(newSection, cell, &off));
3916852b71a7SToby Isaac   for (PetscInt c = 0, pos = off; c < P4EST_CHILDREN; c++) {
3917852b71a7SToby Isaac     p4est_qcoord_t quad_coords[3];
3918852b71a7SToby Isaac     p4est_qcoord_t h = P4EST_QUADRANT_LEN(quad->level);
3919852b71a7SToby Isaac     double         corner_coords[3];
3920852b71a7SToby Isaac     PetscInt       corner = PetscVertToP4estVert[c];
3921852b71a7SToby Isaac 
3922852b71a7SToby Isaac     quad_coords[0] = quad->x;
3923852b71a7SToby Isaac     quad_coords[1] = quad->y;
3924852b71a7SToby Isaac   #ifdef P4_TO_P8
3925852b71a7SToby Isaac     quad_coords[2] = quad->z;
3926852b71a7SToby Isaac   #endif
3927ad540459SPierre Jolivet     for (int d = 0; d < 3; d++) quad_coords[d] += (corner & (1 << d)) ? h : 0;
3928852b71a7SToby Isaac   #ifndef P4_TO_P8
3929648bc8c4SBarry Smith     PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3930852b71a7SToby Isaac   #else
3931648bc8c4SBarry Smith     PetscCallP4est(p4est_qcoord_to_vertex, (pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3932852b71a7SToby Isaac   #endif
3933ad540459SPierre Jolivet     for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) coords[pos++] = corner_coords[d];
3934ad540459SPierre Jolivet     for (PetscInt d = PetscMin(cDim, 3); d < cDim; d++) coords[pos++] = 0.;
3935852b71a7SToby Isaac   }
39363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
3937852b71a7SToby Isaac }
3938852b71a7SToby Isaac 
3939d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
3940d71ae5a4SJacob Faibussowitsch {
39410a96aa3bSJed Brown   DM_Forest         *forest;
39420a96aa3bSJed Brown   DM_Forest_pforest *pforest;
39436858538eSMatthew G. Knepley   DM                 base, cdm, cdmCell;
3944852b71a7SToby Isaac   Vec                cVec, cVecOld;
3945852b71a7SToby Isaac   PetscSection       oldSection, newSection;
39460a96aa3bSJed Brown   PetscScalar       *coords2;
39476858538eSMatthew G. Knepley   const PetscReal   *L;
39480a96aa3bSJed Brown   PetscInt           cLocalStart, cLocalEnd, coarsePoint;
3949852b71a7SToby Isaac   PetscInt           cDim, newStart, newEnd;
3950852b71a7SToby Isaac   PetscInt           v, vStart, vEnd, cp, cStart, cEnd, cEndInterior;
39510a96aa3bSJed Brown   p4est_topidx_t     flt, llt, t;
39520a96aa3bSJed Brown   p4est_tree_t      *trees;
39536858538eSMatthew G. Knepley   PetscBool          baseLocalized = PETSC_FALSE;
39540a96aa3bSJed Brown 
39550a96aa3bSJed Brown   PetscFunctionBegin;
39564fb89dddSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dm, NULL, NULL, &L));
39570a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
39589566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cDim));
39599566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
39606858538eSMatthew G. Knepley   if (base) PetscCall(DMGetCoordinatesLocalized(base, &baseLocalized));
39610a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
39623ba16761SJacob Faibussowitsch   if (!baseLocalized && !L) PetscFunctionReturn(PETSC_SUCCESS);
39639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &newStart, &newEnd));
39640a96aa3bSJed Brown 
39659566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dm), &newSection));
39669566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(newSection, 1));
39679566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim));
39689566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSection, newStart, newEnd));
39690a96aa3bSJed Brown 
39709566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &oldSection));
39719566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
3972852b71a7SToby Isaac   PetscCall(DMGetCoordinatesLocal(plex, &cVecOld));
39730a96aa3bSJed Brown 
39740a96aa3bSJed Brown   forest      = (DM_Forest *)dm->data;
39750a96aa3bSJed Brown   pforest     = (DM_Forest_pforest *)forest->data;
39760a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
39770a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
39780a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
39790a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
39800a96aa3bSJed Brown   trees       = (p4est_tree_t *)pforest->forest->trees->array;
39810a96aa3bSJed Brown 
39829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
39832827ebadSStefano Zampini   PetscCall(DMPlexGetCellTypeStratum(plex, DM_POLYTOPE_FV_GHOST, &cEndInterior, NULL));
39840a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
3985852b71a7SToby Isaac   cp   = 0;
39860a96aa3bSJed Brown   if (cLocalStart > 0) {
39870a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
3988852b71a7SToby Isaac     PetscInt          cell;
39890a96aa3bSJed Brown 
3990852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
3991852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
3992852b71a7SToby Isaac 
39930a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
3994852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
39950a96aa3bSJed Brown     }
39960a96aa3bSJed Brown   }
39970a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
3998*f4f49eeaSPierre Jolivet     p4est_tree_t     *tree     = &trees[t];
39990a96aa3bSJed Brown     PetscInt          offset   = cLocalStart + tree->quadrants_offset;
40000a96aa3bSJed Brown     PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
4001852b71a7SToby Isaac     p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
40020a96aa3bSJed Brown     PetscInt          i;
40030a96aa3bSJed Brown 
40040a96aa3bSJed Brown     if (!numQuads) continue;
40050a96aa3bSJed Brown     coarsePoint = t;
4006852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4007852b71a7SToby Isaac       PetscInt          cell = i + offset;
4008852b71a7SToby Isaac       p4est_quadrant_t *quad = &quads[i];
40090a96aa3bSJed Brown 
4010852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
40110a96aa3bSJed Brown     }
40120a96aa3bSJed Brown   }
40130a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
40140a96aa3bSJed Brown     p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
40150a96aa3bSJed Brown     PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
40160a96aa3bSJed Brown     PetscInt          count;
40170a96aa3bSJed Brown 
4018852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
40190a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
40200a96aa3bSJed Brown       coarsePoint            = quad->p.which_tree;
4021852b71a7SToby Isaac       PetscInt cell          = count + cLocalEnd;
40220a96aa3bSJed Brown 
4023852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
40240a96aa3bSJed Brown     }
40250a96aa3bSJed Brown   }
4026852b71a7SToby Isaac   PetscAssert(cp == cEnd - cStart, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT, cp, cEnd - cStart);
40270a96aa3bSJed Brown 
40289566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSection));
40296858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(plex, &cdm));
40306858538eSMatthew G. Knepley   PetscCall(DMClone(cdm, &cdmCell));
40316858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(plex, cdmCell));
40326858538eSMatthew G. Knepley   PetscCall(DMDestroy(&cdmCell));
40336858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateSection(plex, cDim, newSection));
40349566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &v));
40359566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
40369566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)cVec, "coordinates"));
40379566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(cVec, cDim));
40389566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE));
40399566063dSJacob Faibussowitsch   PetscCall(VecSetType(cVec, VECSTANDARD));
40409566063dSJacob Faibussowitsch   PetscCall(VecSet(cVec, PETSC_MIN_REAL));
40410a96aa3bSJed Brown 
40420a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
40436858538eSMatthew G. Knepley   PetscCall(VecGetArray(cVec, &coords2));
4044852b71a7SToby Isaac   cp = 0;
4045852b71a7SToby Isaac   if (cLocalStart > 0) {
4046852b71a7SToby Isaac     p4est_quadrant_t *ghosts = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
4047852b71a7SToby Isaac     PetscInt          cell;
4048852b71a7SToby Isaac 
4049852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
4050852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
4051852b71a7SToby Isaac 
4052852b71a7SToby Isaac       coarsePoint = quad->p.which_tree;
4053852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4054852b71a7SToby Isaac     }
4055852b71a7SToby Isaac   }
40560a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
4057*f4f49eeaSPierre Jolivet     p4est_tree_t     *tree     = &trees[t];
40580a96aa3bSJed Brown     PetscInt          offset   = cLocalStart + tree->quadrants_offset;
40590a96aa3bSJed Brown     PetscInt          numQuads = (PetscInt)tree->quadrants.elem_count;
4060852b71a7SToby Isaac     p4est_quadrant_t *quads    = (p4est_quadrant_t *)tree->quadrants.array;
4061852b71a7SToby Isaac     PetscInt          i;
40620a96aa3bSJed Brown 
40630a96aa3bSJed Brown     if (!numQuads) continue;
4064852b71a7SToby Isaac     coarsePoint = t;
4065852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4066852b71a7SToby Isaac       PetscInt          cell = i + offset;
40670a96aa3bSJed Brown       p4est_quadrant_t *quad = &quads[i];
40680a96aa3bSJed Brown 
4069852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4070852b71a7SToby Isaac     }
4071852b71a7SToby Isaac   }
4072852b71a7SToby Isaac   if (cLocalEnd - cLocalStart < cEnd - cStart) {
4073852b71a7SToby Isaac     p4est_quadrant_t *ghosts    = (p4est_quadrant_t *)pforest->ghost->ghosts.array;
4074852b71a7SToby Isaac     PetscInt          numGhosts = (PetscInt)pforest->ghost->ghosts.elem_count;
4075852b71a7SToby Isaac     PetscInt          count;
40760a96aa3bSJed Brown 
4077852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
4078852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
4079852b71a7SToby Isaac       coarsePoint            = quad->p.which_tree;
4080852b71a7SToby Isaac       PetscInt cell          = count + cLocalEnd;
40810a96aa3bSJed Brown 
4082852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
40830a96aa3bSJed Brown     }
40840a96aa3bSJed Brown   }
40859566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cVec, &coords2));
40866858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(plex, cVec));
40879566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cVec));
40889566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&newSection));
40893ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
40900a96aa3bSJed Brown }
40910a96aa3bSJed Brown 
40920a96aa3bSJed Brown   #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
4093d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
4094d71ae5a4SJacob Faibussowitsch {
40950a96aa3bSJed Brown   DM_Forest         *forest;
40960a96aa3bSJed Brown   DM_Forest_pforest *pforest;
40970a96aa3bSJed Brown 
40980a96aa3bSJed Brown   PetscFunctionBegin;
40990a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
41000a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
4101*f4f49eeaSPierre Jolivet   PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
4102*f4f49eeaSPierre Jolivet   PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
41039566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
41049566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
41053ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
41060a96aa3bSJed Brown }
41070a96aa3bSJed Brown 
4108d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
4109d71ae5a4SJacob Faibussowitsch {
41100a96aa3bSJed Brown   DM_Forest           *forest;
41110a96aa3bSJed Brown   DM_Forest_pforest   *pforest;
41120a96aa3bSJed Brown   DM                   refTree, newPlex, base;
41130a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
41140a96aa3bSJed Brown   MPI_Comm             comm;
41150a96aa3bSJed Brown   PetscBool            isPforest;
41160a96aa3bSJed Brown   PetscInt             dim;
41170a96aa3bSJed Brown   PetscInt             overlap;
41180a96aa3bSJed Brown   p4est_connect_type_t ctype;
41190a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
41200a96aa3bSJed Brown   sc_array_t          *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
41210a96aa3bSJed Brown   PetscSection         parentSection;
41220a96aa3bSJed Brown   PetscSF              pointSF;
41230a96aa3bSJed Brown   size_t               zz, count;
41240a96aa3bSJed Brown   PetscInt             pStart, pEnd;
41250a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
41260a96aa3bSJed Brown 
41270a96aa3bSJed Brown   PetscFunctionBegin;
41280a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
41290a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
41309566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm, DMPFOREST, &isPforest));
413128b400f6SJacob Faibussowitsch   PetscCheck(isPforest, comm, PETSC_ERR_ARG_WRONG, "Expected DM type %s, got %s", DMPFOREST, ((PetscObject)dm)->type_name);
41329566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm, &dim));
413363a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM, comm, PETSC_ERR_ARG_WRONG, "Expected DM dimension %d, got %" PetscInt_FMT, P4EST_DIM, dim);
41340a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
41350a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
41369566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
413748a46eb9SPierre Jolivet   if (base) PetscCall(DMGetLabel(base, "ghost", &ghostLabelBase));
41380a96aa3bSJed Brown   if (!pforest->plex) {
41390a96aa3bSJed Brown     PetscMPIInt size;
41400a96aa3bSJed Brown 
41419566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm, &size));
41429566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm, &newPlex));
41439566063dSJacob Faibussowitsch     PetscCall(DMSetType(newPlex, DMPLEX));
41449566063dSJacob Faibussowitsch     PetscCall(DMSetMatType(newPlex, dm->mattype));
41450a96aa3bSJed Brown     /* share labels */
41469566063dSJacob Faibussowitsch     PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
41479566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyDimension(dm, &adjDim));
41489566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyCodimension(dm, &adjCodim));
41499566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
41500a96aa3bSJed Brown     if (adjDim == 0) {
41510a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
41520a96aa3bSJed Brown     } else if (adjCodim == 1) {
41530a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
41540a96aa3bSJed Brown   #if defined(P4_TO_P8)
41550a96aa3bSJed Brown     } else if (adjDim == 1) {
41560a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
41570a96aa3bSJed Brown   #endif
41580a96aa3bSJed Brown     } else {
415963a3b9bcSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_ARG_WRONG, "Invalid adjacency dimension %" PetscInt_FMT, adjDim);
41600a96aa3bSJed Brown     }
416163a3b9bcSJacob 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);
41629566063dSJacob Faibussowitsch     PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
416360667520SVaclav Hapla     PetscCall(DMPlexSetOverlap_Plex(newPlex, NULL, overlap));
41640a96aa3bSJed Brown 
41650a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
41660a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
41670a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
41680a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
41690a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
41700a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
41710a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
41720a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
41730a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
41740a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
41750a96aa3bSJed Brown 
4176792fecdfSBarry 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));
41770a96aa3bSJed Brown 
41780a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt)first_local_quad;
41790a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt)pforest->forest->local_num_quadrants;
41809566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
41819566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
41829566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
41839566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
41849566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, coordDim));
41859566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(children));
41869566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(parents));
41879566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(childids));
41889566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(leaves));
41899566063dSJacob Faibussowitsch     PetscCall(locidx_pair_to_PetscSFNode(remotes));
41900a96aa3bSJed Brown 
41919566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(newPlex, P4EST_DIM));
41929566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDim(newPlex, coordDim));
41939566063dSJacob Faibussowitsch     PetscCall(DMPlexSetMaxProjectionHeight(newPlex, P4EST_DIM - 1));
41949566063dSJacob 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));
41959566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(newPlex));
41969566063dSJacob Faibussowitsch     PetscCall(DMCreateReferenceTree_pforest(comm, &refTree));
41979566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(newPlex, refTree));
41989566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(comm, &parentSection));
41999566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(newPlex, &pStart, &pEnd));
42009566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection, pStart, pEnd));
42010a96aa3bSJed Brown     count = children->elem_count;
42020a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
42030a96aa3bSJed Brown       PetscInt child = *((PetscInt *)sc_array_index(children, zz));
42040a96aa3bSJed Brown 
42059566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(parentSection, child, 1));
42060a96aa3bSJed Brown     }
42079566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
42089566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(newPlex, parentSection, (PetscInt *)parents->array, (PetscInt *)childids->array));
42099566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&parentSection));
42109566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm, &pointSF));
42110a96aa3bSJed Brown     /*
42120a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
42130a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
42140a96aa3bSJed Brown     */
42159566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(pointSF, pEnd - pStart, (PetscInt)leaves->elem_count, (PetscInt *)leaves->array, PETSC_COPY_VALUES, (PetscSFNode *)remotes->array, PETSC_COPY_VALUES));
42169566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(newPlex, pointSF));
42179566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(dm, pointSF));
42180a96aa3bSJed Brown     {
42190a96aa3bSJed Brown       DM coordDM;
42200a96aa3bSJed Brown 
42219566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex, &coordDM));
42229566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(coordDM, pointSF));
42230a96aa3bSJed Brown     }
42249566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointSF));
42250a96aa3bSJed Brown     sc_array_destroy(points_per_dim);
42260a96aa3bSJed Brown     sc_array_destroy(cone_sizes);
42270a96aa3bSJed Brown     sc_array_destroy(cones);
42280a96aa3bSJed Brown     sc_array_destroy(cone_orientations);
42290a96aa3bSJed Brown     sc_array_destroy(coords);
42300a96aa3bSJed Brown     sc_array_destroy(children);
42310a96aa3bSJed Brown     sc_array_destroy(parents);
42320a96aa3bSJed Brown     sc_array_destroy(childids);
42330a96aa3bSJed Brown     sc_array_destroy(leaves);
42340a96aa3bSJed Brown     sc_array_destroy(remotes);
42350a96aa3bSJed Brown 
42360a96aa3bSJed Brown     {
42374fb89dddSMatthew G. Knepley       const PetscReal *maxCell, *Lstart, *L;
42380a96aa3bSJed Brown 
42394fb89dddSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm, &maxCell, &Lstart, &L));
42404fb89dddSMatthew G. Knepley       PetscCall(DMSetPeriodicity(newPlex, maxCell, Lstart, L));
42419566063dSJacob Faibussowitsch       PetscCall(DMPforestLocalizeCoordinates(dm, newPlex));
42420a96aa3bSJed Brown     }
42430a96aa3bSJed Brown 
42440a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
42450a96aa3bSJed Brown       Vec                coordsGlobal, coordsLocal;
42460a96aa3bSJed Brown       const PetscScalar *globalArray;
42470a96aa3bSJed Brown       PetscScalar       *localArray;
42480a96aa3bSJed Brown       PetscSF            coordSF;
42490a96aa3bSJed Brown       DM                 coordDM;
42500a96aa3bSJed Brown 
42519566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex, &coordDM));
42529566063dSJacob Faibussowitsch       PetscCall(DMGetSectionSF(coordDM, &coordSF));
42539566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinates(newPlex, &coordsGlobal));
42549566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal));
42559566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordsGlobal, &globalArray));
42569566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordsLocal, &localArray));
42579566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coordSF, MPIU_SCALAR, globalArray, localArray, MPI_REPLACE));
42589566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coordSF, MPIU_SCALAR, globalArray, localArray, MPI_REPLACE));
42599566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordsLocal, &localArray));
42609566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray));
42619566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal));
42620a96aa3bSJed Brown     }
42639566063dSJacob Faibussowitsch     PetscCall(DMPforestMapCoordinates(dm, newPlex));
42640a96aa3bSJed Brown 
42650a96aa3bSJed Brown     pforest->plex = newPlex;
42660a96aa3bSJed Brown 
42670a96aa3bSJed Brown     /* copy labels */
42689566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsFinalize(dm, newPlex));
42690a96aa3bSJed Brown 
42700a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
42710a96aa3bSJed Brown       PetscInt numAdded;
42720a96aa3bSJed Brown       DM       newPlexGhosted;
42730a96aa3bSJed Brown       void    *ctx;
42740a96aa3bSJed Brown 
42759566063dSJacob Faibussowitsch       PetscCall(DMPlexConstructGhostCells(newPlex, pforest->ghostName, &numAdded, &newPlexGhosted));
42769566063dSJacob Faibussowitsch       PetscCall(DMGetApplicationContext(newPlex, &ctx));
42779566063dSJacob Faibussowitsch       PetscCall(DMSetApplicationContext(newPlexGhosted, ctx));
42780a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
42799566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(newPlexGhosted, &pointSF));
42809566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(dm, pointSF));
42819566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&newPlex));
42829566063dSJacob Faibussowitsch       PetscCall(DMPlexSetReferenceTree(newPlexGhosted, refTree));
42839566063dSJacob Faibussowitsch       PetscCall(DMForestClearAdaptivityForest_pforest(dm));
42840a96aa3bSJed Brown       newPlex = newPlexGhosted;
42850a96aa3bSJed Brown 
42860a96aa3bSJed Brown       /* share the labels back */
42879566063dSJacob Faibussowitsch       PetscCall(DMDestroyLabelLinkList_Internal(dm));
42889566063dSJacob Faibussowitsch       PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
42890a96aa3bSJed Brown       pforest->plex = newPlex;
42900a96aa3bSJed Brown     }
42919566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&refTree));
42920a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
4293d0609cedSBarry Smith       PetscObjectOptionsBegin((PetscObject)newPlex);
4294dbbe0bcdSBarry Smith       PetscCall(DMSetFromOptions_NonRefinement_Plex(newPlex, PetscOptionsObject));
4295dbbe0bcdSBarry Smith       PetscCall(PetscObjectProcessOptionsHandlers((PetscObject)newPlex, PetscOptionsObject));
4296d0609cedSBarry Smith       PetscOptionsEnd();
42970a96aa3bSJed Brown     }
42989566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(newPlex, NULL, "-dm_p4est_plex_view"));
42990a96aa3bSJed Brown     {
43006858538eSMatthew G. Knepley       DM           cdm;
43010a96aa3bSJed Brown       PetscSection coordsSec;
43020a96aa3bSJed Brown       Vec          coords;
43030a96aa3bSJed Brown       PetscInt     cDim;
43040a96aa3bSJed Brown 
43059566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(newPlex, &cDim));
43069566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(newPlex, &coordsSec));
43079566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinateSection(dm, cDim, coordsSec));
43089566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coords));
43099566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(dm, coords));
43106858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateDM(newPlex, &cdm));
43116858538eSMatthew G. Knepley       if (cdm) PetscCall(DMSetCellCoordinateDM(dm, cdm));
43126858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateSection(newPlex, &coordsSec));
43136858538eSMatthew G. Knepley       if (coordsSec) PetscCall(DMSetCellCoordinateSection(dm, cDim, coordsSec));
43146858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinatesLocal(newPlex, &coords));
43156858538eSMatthew G. Knepley       if (coords) PetscCall(DMSetCellCoordinatesLocal(dm, coords));
43160a96aa3bSJed Brown     }
4317cdf84abbSMatthew G. Knepley   } else {
4318cdf84abbSMatthew G. Knepley     PetscCall(DMCopyLabels(dm, pforest->plex, PETSC_OWN_POINTER, PETSC_FALSE, DM_COPY_LABELS_REPLACE));
43190a96aa3bSJed Brown   }
43200a96aa3bSJed Brown   newPlex = pforest->plex;
43210a96aa3bSJed Brown   if (plex) {
43229566063dSJacob Faibussowitsch     PetscCall(DMClone(newPlex, plex));
43236858538eSMatthew G. Knepley   #if 0
43249566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43259566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDM(*plex,coordDM));
43266858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(newPlex,&coordDM));
43276858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*plex,coordDM));
43286858538eSMatthew G. Knepley   #endif
43299566063dSJacob Faibussowitsch     PetscCall(DMShareDiscretization(dm, *plex));
43300a96aa3bSJed Brown   }
43313ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43320a96aa3bSJed Brown }
43330a96aa3bSJed Brown 
4334d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMSetFromOptions_pforest(DM dm, PetscOptionItems *PetscOptionsObject)
4335d71ae5a4SJacob Faibussowitsch {
43360a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43370a96aa3bSJed Brown   char               stringBuffer[256];
43380a96aa3bSJed Brown   PetscBool          flg;
43390a96aa3bSJed Brown 
43400a96aa3bSJed Brown   PetscFunctionBegin;
4341dbbe0bcdSBarry Smith   PetscCall(DMSetFromOptions_Forest(dm, PetscOptionsObject));
4342d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject, "DM" P4EST_STRING " options");
4343217f96c1SStefano Zampini   PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening", "partition forest to allow for coarsening", "DMP4estSetPartitionForCoarsening", pforest->partition_for_coarsening, &pforest->partition_for_coarsening, NULL));
43449566063dSJacob 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));
4345d0609cedSBarry Smith   PetscOptionsHeadEnd();
43460a96aa3bSJed Brown   if (flg) {
43479566063dSJacob Faibussowitsch     PetscCall(PetscFree(pforest->ghostName));
43489566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(stringBuffer, &pforest->ghostName));
43490a96aa3bSJed Brown   }
43503ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43510a96aa3bSJed Brown }
43520a96aa3bSJed Brown 
43530a96aa3bSJed Brown   #if !defined(P4_TO_P8)
43540a96aa3bSJed Brown     #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
43550a96aa3bSJed Brown     #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
43560a96aa3bSJed Brown   #else
43570a96aa3bSJed Brown     #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
43580a96aa3bSJed Brown     #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
43590a96aa3bSJed Brown   #endif
43600a96aa3bSJed Brown 
4361d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
4362d71ae5a4SJacob Faibussowitsch {
43630a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43640a96aa3bSJed Brown 
43650a96aa3bSJed Brown   PetscFunctionBegin;
43660a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43670a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43680a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
43693ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43700a96aa3bSJed Brown }
43710a96aa3bSJed Brown 
4372d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
4373d71ae5a4SJacob Faibussowitsch {
43740a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43750a96aa3bSJed Brown 
43760a96aa3bSJed Brown   PetscFunctionBegin;
43770a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
43780a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
43790a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
43803ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43810a96aa3bSJed Brown }
43820a96aa3bSJed Brown 
4383d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMPforestGetPlex(DM dm, DM *plex)
4384d71ae5a4SJacob Faibussowitsch {
43850a96aa3bSJed Brown   DM_Forest_pforest *pforest;
43860a96aa3bSJed Brown 
43870a96aa3bSJed Brown   PetscFunctionBegin;
43880a96aa3bSJed Brown   if (plex) *plex = NULL;
43899566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
43900a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)((DM_Forest *)dm->data)->data;
439148a46eb9SPierre Jolivet   if (!pforest->plex) PetscCall(DMConvert_pforest_plex(dm, DMPLEX, NULL));
43929566063dSJacob Faibussowitsch   PetscCall(DMShareDiscretization(dm, pforest->plex));
43930a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
43943ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
43950a96aa3bSJed Brown }
43960a96aa3bSJed Brown 
43970a96aa3bSJed Brown   #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
4398d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
4399d71ae5a4SJacob Faibussowitsch {
44000a96aa3bSJed Brown   PetscSection gsc, gsf;
44010a96aa3bSJed Brown   PetscInt     m, n;
44020a96aa3bSJed Brown   DM           cdm;
44030a96aa3bSJed Brown 
44040a96aa3bSJed Brown   PetscFunctionBegin;
44059566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
44069566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
44079566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
44089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
44090a96aa3bSJed Brown 
44109566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmFine), interpolation));
44119566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
44129566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, MATAIJ));
44130a96aa3bSJed Brown 
44149566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
441508401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse, PetscObjectComm((PetscObject)dmFine), PETSC_ERR_SUP, "Only interpolation from coarse DM for now");
44160a96aa3bSJed Brown 
44170a96aa3bSJed Brown   {
44180a96aa3bSJed Brown     DM        plexF, plexC;
44190a96aa3bSJed Brown     PetscSF   sf;
44200a96aa3bSJed Brown     PetscInt *cids;
44210a96aa3bSJed Brown     PetscInt  dofPerDim[4] = {1, 1, 1, 1};
44220a96aa3bSJed Brown 
44239566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse, &plexC));
44249566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine, &plexF));
44259566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
44269566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
44279566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
44289566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
44299566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
44300a96aa3bSJed Brown   }
44319566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
44320a96aa3bSJed Brown   /* Use naive scaling */
44339566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
44343ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44350a96aa3bSJed Brown }
44360a96aa3bSJed Brown 
44370a96aa3bSJed Brown   #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
4438d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
4439d71ae5a4SJacob Faibussowitsch {
44400a96aa3bSJed Brown   PetscSection gsc, gsf;
44410a96aa3bSJed Brown   PetscInt     m, n;
44420a96aa3bSJed Brown   DM           cdm;
44430a96aa3bSJed Brown 
44440a96aa3bSJed Brown   PetscFunctionBegin;
44459566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
44469566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n));
44479566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
44489566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m));
44490a96aa3bSJed Brown 
44509566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject)dmFine), injection));
44519566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
44529566063dSJacob Faibussowitsch   PetscCall(MatSetType(*injection, MATAIJ));
44530a96aa3bSJed Brown 
44549566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
445508401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse, PetscObjectComm((PetscObject)dmFine), PETSC_ERR_SUP, "Only injection to coarse DM for now");
44560a96aa3bSJed Brown 
44570a96aa3bSJed Brown   {
44580a96aa3bSJed Brown     DM        plexF, plexC;
44590a96aa3bSJed Brown     PetscSF   sf;
44600a96aa3bSJed Brown     PetscInt *cids;
44610a96aa3bSJed Brown     PetscInt  dofPerDim[4] = {1, 1, 1, 1};
44620a96aa3bSJed Brown 
44639566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse, &plexC));
44649566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine, &plexF));
44659566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
44669566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
44679566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
44689566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
44699566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
44700a96aa3bSJed Brown   }
44719566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
44720a96aa3bSJed Brown   /* Use naive scaling */
44733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
44740a96aa3bSJed Brown }
44750a96aa3bSJed Brown 
44760a96aa3bSJed Brown   #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
4477d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
4478d71ae5a4SJacob Faibussowitsch {
44790a96aa3bSJed Brown   DM        dmIn, dmVecIn, base, basec, plex, coarseDM;
44800a96aa3bSJed Brown   DM       *hierarchy;
44810a96aa3bSJed Brown   PetscSF   sfRed = NULL;
44820a96aa3bSJed Brown   PetscDS   ds;
44830a96aa3bSJed Brown   Vec       vecInLocal, vecOutLocal;
44840a96aa3bSJed Brown   DMLabel   subpointMap;
44850a96aa3bSJed Brown   PetscInt  minLevel, mh, n_hi, i;
44860a96aa3bSJed Brown   PetscBool hiforest, *hierarchy_forest;
44870a96aa3bSJed Brown 
44880a96aa3bSJed Brown   PetscFunctionBegin;
44899566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vecIn, &dmVecIn));
44909566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmVecIn, &ds));
449128b400f6SJacob Faibussowitsch   PetscCheck(ds, PetscObjectComm((PetscObject)dmVecIn), PETSC_ERR_SUP, "Cannot transfer without a PetscDS object");
44920a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
44930a96aa3bSJed Brown     PetscSection section;
44940a96aa3bSJed Brown     PetscInt     Nf;
44950a96aa3bSJed Brown 
44969566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn, &section));
44979566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section, &Nf));
449863a3b9bcSJacob 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);
44990a96aa3bSJed Brown   }
45009566063dSJacob Faibussowitsch   PetscCall(DMForestGetMinimumRefinement(dm, &minLevel));
450163a3b9bcSJacob Faibussowitsch   PetscCheck(!minLevel, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)", minLevel);
45029566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm, &base));
450328b400f6SJacob Faibussowitsch   PetscCheck(base, PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "Missing base DM");
45040a96aa3bSJed Brown 
45059566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut, 0.0));
45060a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
45079566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45080a96aa3bSJed Brown   } else {
45090a96aa3bSJed Brown     PetscSection secIn, secInRed;
45100a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
45110a96aa3bSJed Brown 
45129566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)base, "_base_migration_sf", (PetscObject *)&sfRed));
451328b400f6SJacob Faibussowitsch     PetscCheck(sfRed, PETSC_COMM_SELF, PETSC_ERR_SUP, "Not the DM set with DMForestSetBaseDM()");
45149566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn), &secInRed));
45159566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF, &vecInRed));
45169566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn, &secIn));
45179566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmVecIn, &vecInLocal));
45189566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmVecIn, vecIn, INSERT_VALUES, vecInLocal));
45199566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmVecIn, vecIn, INSERT_VALUES, vecInLocal));
45209566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeField(dmVecIn, sfRed, secIn, vecInLocal, secInRed, vecInRed));
45219566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmVecIn, &vecInLocal));
45229566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secInRed));
45230a96aa3bSJed Brown     vecIn = vecInRed;
45240a96aa3bSJed Brown   }
45250a96aa3bSJed Brown 
45260a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
45270a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
45280a96aa3bSJed Brown   hiforest = PETSC_TRUE;
45290a96aa3bSJed Brown 
45300a96aa3bSJed Brown   /* upsweep to the coarsest DM */
45310a96aa3bSJed Brown   n_hi     = 0;
45320a96aa3bSJed Brown   coarseDM = dm;
45330a96aa3bSJed Brown   do {
45340a96aa3bSJed Brown     PetscBool isforest;
45350a96aa3bSJed Brown 
45360a96aa3bSJed Brown     dmIn = coarseDM;
45370a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
45389566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dmIn));
45399566063dSJacob Faibussowitsch     PetscCall(DMIsForest(dmIn, &isforest));
454028b400f6SJacob Faibussowitsch     PetscCheck(isforest, PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "Cannot currently transfer through a mixed hierarchy! Found DM type %s", ((PetscObject)dmIn)->type_name);
45410a96aa3bSJed Brown     coarseDM = NULL;
454248a46eb9SPierre Jolivet     if (hiforest) PetscCall(DMForestGetAdaptivityForest(dmIn, &coarseDM));
45430a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
45440a96aa3bSJed Brown       hiforest = PETSC_FALSE;
45459566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn, &coarseDM));
45460a96aa3bSJed Brown     }
45470a96aa3bSJed Brown     n_hi++;
45480a96aa3bSJed Brown   } while (coarseDM);
45490a96aa3bSJed Brown 
45509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n_hi, &hierarchy, n_hi, &hierarchy_forest));
45510a96aa3bSJed Brown 
45520a96aa3bSJed Brown   i        = 0;
45530a96aa3bSJed Brown   hiforest = PETSC_TRUE;
45540a96aa3bSJed Brown   coarseDM = dm;
45550a96aa3bSJed Brown   do {
45560a96aa3bSJed Brown     dmIn     = coarseDM;
45570a96aa3bSJed Brown     coarseDM = NULL;
455848a46eb9SPierre Jolivet     if (hiforest) PetscCall(DMForestGetAdaptivityForest(dmIn, &coarseDM));
45590a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
45600a96aa3bSJed Brown       hiforest = PETSC_FALSE;
45619566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn, &coarseDM));
45620a96aa3bSJed Brown     }
45630a96aa3bSJed Brown     i++;
45640a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
45650a96aa3bSJed Brown   } while (coarseDM);
45660a96aa3bSJed Brown 
45670a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
45689566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn, &plex));
45690a96aa3bSJed Brown 
45700a96aa3bSJed Brown   /* Check this plex is compatible with the base */
45710a96aa3bSJed Brown   {
45720a96aa3bSJed Brown     IS       gnum[2];
45730a96aa3bSJed Brown     PetscInt ncells[2], gncells[2];
45740a96aa3bSJed Brown 
45759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(base, &gnum[0]));
45769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(plex, &gnum[1]));
45779566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[0], NULL, &ncells[0]));
45789566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[1], NULL, &ncells[1]));
45791c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(ncells, gncells, 2, MPIU_INT, MPI_MAX, PetscObjectComm((PetscObject)dm)));
458063a3b9bcSJacob 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);
45810a96aa3bSJed Brown   }
45820a96aa3bSJed Brown 
45839566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dmIn, "_forest_base_subpoint_map", &subpointMap));
458428b400f6SJacob Faibussowitsch   PetscCheck(subpointMap, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Missing _forest_base_subpoint_map label");
45850a96aa3bSJed Brown 
45869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(base, &mh));
45879566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(plex, mh));
45880a96aa3bSJed Brown 
45899566063dSJacob Faibussowitsch   PetscCall(DMClone(base, &basec));
45909566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmVecIn, basec));
45910a96aa3bSJed Brown   if (sfRed) {
45929566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45930a96aa3bSJed Brown     vecInLocal = vecIn;
45940a96aa3bSJed Brown   } else {
45959566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(basec, &vecInLocal));
45969566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(basec, vecIn, INSERT_VALUES, vecInLocal));
45979566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(basec, vecIn, INSERT_VALUES, vecInLocal));
45980a96aa3bSJed Brown   }
45990a96aa3bSJed Brown 
46009566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmIn, &vecOutLocal));
46010a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
46020a96aa3bSJed Brown     PetscSF            basetocoarse;
46030a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
46040a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
46050a96aa3bSJed Brown     PetscMPIInt        rank;
46060a96aa3bSJed Brown     PetscSFNode       *remotes;
46070a96aa3bSJed Brown     PetscSection       secIn, secOut;
46080a96aa3bSJed Brown     PetscInt          *remoteOffsets;
46090a96aa3bSJed Brown     PetscSF            transferSF;
46100a96aa3bSJed Brown     const PetscScalar *inArray;
46110a96aa3bSJed Brown     PetscScalar       *outArray;
46120a96aa3bSJed Brown 
46139566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
46149566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(basec, &bStart, &bEnd));
46150a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
46169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &iStart, &iEnd));
46170a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
46180a96aa3bSJed Brown 
46199566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &remotes));
46200a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
46210a96aa3bSJed Brown       PetscInt index;
46220a96aa3bSJed Brown 
46230a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
46249566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(subpointMap, leaf, &index));
46250a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
46260a96aa3bSJed Brown     }
46270a96aa3bSJed Brown 
46289566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
46299566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
46309566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(basetocoarse));
46319566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(basec, &secIn));
46329566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn), &secOut));
46339566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
46349566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
46359566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
46369566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(vecOutLocal, &outArray));
46379566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecInLocal, &inArray));
46389566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray, MPI_REPLACE));
46399566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray, MPI_REPLACE));
46409566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecInLocal, &inArray));
46419566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray));
46429566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferSF));
46439566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secOut));
46449566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&basetocoarse));
46450a96aa3bSJed Brown   }
46469566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecInLocal));
46479566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&basec));
46489566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecIn));
46490a96aa3bSJed Brown 
46500a96aa3bSJed Brown   /* output */
46510a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
46520a96aa3bSJed Brown     Vec vecOut1, vecOut2;
46530a96aa3bSJed Brown     DM  fineDM;
46540a96aa3bSJed Brown 
46559566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmIn, &vecOut1));
46569566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn, vecOutLocal, INSERT_VALUES, vecOut1));
46579566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecOutLocal));
46580a96aa3bSJed Brown     for (i = 1; i < n_hi - 1; i++) {
46590a96aa3bSJed Brown       fineDM = hierarchy[i];
46609566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(fineDM, &vecOut2));
46619566063dSJacob Faibussowitsch       PetscCall(DMForestTransferVec(dmIn, vecOut1, fineDM, vecOut2, PETSC_TRUE, 0.0));
46629566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmIn, &vecOut1));
46630a96aa3bSJed Brown       vecOut1 = vecOut2;
46640a96aa3bSJed Brown       dmIn    = fineDM;
46650a96aa3bSJed Brown     }
46669566063dSJacob Faibussowitsch     PetscCall(DMForestTransferVec(dmIn, vecOut1, dm, vecOut, PETSC_TRUE, 0.0));
46679566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmIn, &vecOut1));
46680a96aa3bSJed Brown   } else {
46699566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn, vecOutLocal, INSERT_VALUES, vecOut));
46709566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn, &vecOutLocal));
46710a96aa3bSJed Brown   }
46729566063dSJacob Faibussowitsch   PetscCall(PetscFree2(hierarchy, hierarchy_forest));
46733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
46740a96aa3bSJed Brown }
46750a96aa3bSJed Brown 
46760a96aa3bSJed Brown   #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
4677d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
4678d71ae5a4SJacob Faibussowitsch {
46790a96aa3bSJed Brown   DM          adaptIn, adaptOut, plexIn, plexOut;
46800a96aa3bSJed Brown   DM_Forest  *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
46810a96aa3bSJed Brown   PetscInt    dofPerDim[] = {1, 1, 1, 1};
46820a96aa3bSJed Brown   PetscSF     inSF = NULL, outSF = NULL;
46830a96aa3bSJed Brown   PetscInt   *inCids = NULL, *outCids = NULL;
46840a96aa3bSJed Brown   DMAdaptFlag purposeIn, purposeOut;
46850a96aa3bSJed Brown 
46860a96aa3bSJed Brown   PetscFunctionBegin;
46870a96aa3bSJed Brown   forestOut = (DM_Forest *)dmOut->data;
46880a96aa3bSJed Brown   forestIn  = (DM_Forest *)dmIn->data;
46890a96aa3bSJed Brown 
46909566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmOut, &adaptOut));
46919566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmOut, &purposeOut));
46920a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *)adaptOut->data : NULL;
46930a96aa3bSJed Brown 
46949566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmIn, &adaptIn));
46959566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmIn, &purposeIn));
46960a96aa3bSJed Brown   forestAdaptIn = adaptIn ? (DM_Forest *)adaptIn->data : NULL;
46970a96aa3bSJed Brown 
46980a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
46990a96aa3bSJed Brown     switch (purposeOut) {
47000a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47019566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47029566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47030a96aa3bSJed Brown       break;
47040a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
47050a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
47069566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_TRUE, &outCids));
47079566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47080a96aa3bSJed Brown       break;
47090a96aa3bSJed Brown     default:
47109566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47119566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_FALSE, &outCids));
47129566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47139566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47140a96aa3bSJed Brown     }
47150a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
47160a96aa3bSJed Brown     switch (purposeIn) {
47170a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47189566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_TRUE, &inCids));
47199566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47200a96aa3bSJed Brown       break;
47210a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
47220a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
47239566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47249566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47250a96aa3bSJed Brown       break;
47260a96aa3bSJed Brown     default:
47279566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn, dmOut, dofPerDim, &inSF, PETSC_TRUE, &inCids));
47289566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut, dmIn, dofPerDim, &outSF, PETSC_FALSE, &outCids));
47299566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47309566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47310a96aa3bSJed Brown     }
47320a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn), PETSC_ERR_SUP, "Only support transfer from pre-adaptivity to post-adaptivity right now");
47339566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn, &plexIn));
47349566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmOut, &plexOut));
47350a96aa3bSJed Brown 
47369566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferVecTree(plexIn, vecIn, plexOut, vecOut, inSF, outSF, inCids, outCids, useBCs, time));
47379566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
47389566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
47399566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&inSF));
47409566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&outSF));
47419566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
47429566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
47433ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47440a96aa3bSJed Brown }
47450a96aa3bSJed Brown 
47460a96aa3bSJed Brown   #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
4747d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm, DM *cdm)
4748d71ae5a4SJacob Faibussowitsch {
47490a96aa3bSJed Brown   DM plex;
47500a96aa3bSJed Brown 
47510a96aa3bSJed Brown   PetscFunctionBegin;
47520a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
47539566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47549566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(plex, cdm));
47559566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)*cdm));
47563ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47570a96aa3bSJed Brown }
47580a96aa3bSJed Brown 
47590a96aa3bSJed Brown   #define VecViewLocal_pforest _append_pforest(VecViewLocal)
4760d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecViewLocal_pforest(Vec vec, PetscViewer viewer)
4761d71ae5a4SJacob Faibussowitsch {
47620a96aa3bSJed Brown   DM dm, plex;
47630a96aa3bSJed Brown 
47640a96aa3bSJed Brown   PetscFunctionBegin;
47659566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
4766217f96c1SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)dm));
47679566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47689566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47699566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Local(vec, viewer));
47709566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
4771217f96c1SStefano Zampini   PetscCall(DMDestroy(&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));
4782217f96c1SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)dm));
47839566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
47849566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
47859566063dSJacob Faibussowitsch   PetscCall(VecView_Plex(vec, viewer));
47869566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
4787217f96c1SStefano Zampini   PetscCall(DMDestroy(&dm));
47883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
47890a96aa3bSJed Brown }
47900a96aa3bSJed Brown 
47910a96aa3bSJed Brown   #define VecView_pforest_Native _infix_pforest(VecView, _Native)
4792d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecView_pforest_Native(Vec vec, PetscViewer viewer)
4793d71ae5a4SJacob Faibussowitsch {
47940a96aa3bSJed Brown   DM dm, plex;
47950a96aa3bSJed Brown 
47960a96aa3bSJed Brown   PetscFunctionBegin;
47979566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
4798217f96c1SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)dm));
47999566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48009566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
48019566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Native(vec, viewer));
48029566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
4803217f96c1SStefano Zampini   PetscCall(DMDestroy(&dm));
48043ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48050a96aa3bSJed Brown }
48060a96aa3bSJed Brown 
48070a96aa3bSJed Brown   #define VecLoad_pforest _append_pforest(VecLoad)
4808d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecLoad_pforest(Vec vec, PetscViewer viewer)
4809d71ae5a4SJacob Faibussowitsch {
48100a96aa3bSJed Brown   DM dm, plex;
48110a96aa3bSJed Brown 
48120a96aa3bSJed Brown   PetscFunctionBegin;
48139566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
4814217f96c1SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)dm));
48159566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48169566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
48179566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex(vec, viewer));
48189566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
4819217f96c1SStefano Zampini   PetscCall(DMDestroy(&dm));
48203ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48210a96aa3bSJed Brown }
48220a96aa3bSJed Brown 
48230a96aa3bSJed Brown   #define VecLoad_pforest_Native _infix_pforest(VecLoad, _Native)
4824d71ae5a4SJacob Faibussowitsch static PetscErrorCode VecLoad_pforest_Native(Vec vec, PetscViewer viewer)
4825d71ae5a4SJacob Faibussowitsch {
48260a96aa3bSJed Brown   DM dm, plex;
48270a96aa3bSJed Brown 
48280a96aa3bSJed Brown   PetscFunctionBegin;
48299566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec, &dm));
4830217f96c1SStefano Zampini   PetscCall(PetscObjectReference((PetscObject)dm));
48319566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48329566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, plex));
48339566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex_Native(vec, viewer));
48349566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec, dm));
4835217f96c1SStefano Zampini   PetscCall(DMDestroy(&dm));
48363ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48370a96aa3bSJed Brown }
48380a96aa3bSJed Brown 
48390a96aa3bSJed Brown   #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
4840d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateGlobalVector_pforest(DM dm, Vec *vec)
4841d71ae5a4SJacob Faibussowitsch {
48420a96aa3bSJed Brown   PetscFunctionBegin;
48439566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector_Section_Private(dm, vec));
48449566063dSJacob Faibussowitsch   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
48459566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
48469566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
48479566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
48489566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
48493ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48500a96aa3bSJed Brown }
48510a96aa3bSJed Brown 
48520a96aa3bSJed Brown   #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
4853d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateLocalVector_pforest(DM dm, Vec *vec)
4854d71ae5a4SJacob Faibussowitsch {
48550a96aa3bSJed Brown   PetscFunctionBegin;
48569566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector_Section_Private(dm, vec));
48579566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
48583ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48590a96aa3bSJed Brown }
48600a96aa3bSJed Brown 
48610a96aa3bSJed Brown   #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
4862d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateMatrix_pforest(DM dm, Mat *mat)
4863d71ae5a4SJacob Faibussowitsch {
48640a96aa3bSJed Brown   DM plex;
48650a96aa3bSJed Brown 
48660a96aa3bSJed Brown   PetscFunctionBegin;
48670a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48689566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48690a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only; /* maybe this should go into forest->plex */
48702495aca6SStefano Zampini   PetscCall(DMSetMatType(plex, dm->mattype));
48719566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(plex, mat));
48729566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*mat, dm));
48733ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48740a96aa3bSJed Brown }
48750a96aa3bSJed Brown 
48760a96aa3bSJed Brown   #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
4877d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, InsertMode mode, Vec localX)
4878d71ae5a4SJacob Faibussowitsch {
48790a96aa3bSJed Brown   DM plex;
48800a96aa3bSJed Brown 
48810a96aa3bSJed Brown   PetscFunctionBegin;
48820a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48839566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48849566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(plex, time, funcs, ctxs, mode, localX));
48853ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48860a96aa3bSJed Brown }
48870a96aa3bSJed Brown 
48880a96aa3bSJed Brown   #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
4889d71ae5a4SJacob 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)
4890d71ae5a4SJacob Faibussowitsch {
48910a96aa3bSJed Brown   DM plex;
48920a96aa3bSJed Brown 
48930a96aa3bSJed Brown   PetscFunctionBegin;
48940a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
48959566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
48969566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(plex, time, label, numIds, ids, Ncc, comps, funcs, ctxs, mode, localX));
48973ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
48980a96aa3bSJed Brown }
48990a96aa3bSJed Brown 
49000a96aa3bSJed Brown   #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
4901d71ae5a4SJacob 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)
4902d71ae5a4SJacob Faibussowitsch {
49030a96aa3bSJed Brown   DM plex;
49040a96aa3bSJed Brown 
49050a96aa3bSJed Brown   PetscFunctionBegin;
49060a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49079566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49089566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(plex, time, localU, funcs, mode, localX));
49093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49100a96aa3bSJed Brown }
49110a96aa3bSJed Brown 
49120a96aa3bSJed Brown   #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
4913d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal *diff)
4914d71ae5a4SJacob Faibussowitsch {
49150a96aa3bSJed Brown   DM plex;
49160a96aa3bSJed Brown 
49170a96aa3bSJed Brown   PetscFunctionBegin;
49180a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49199566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49209566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(plex, time, funcs, ctxs, X, diff));
49213ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49220a96aa3bSJed Brown }
49230a96aa3bSJed Brown 
49240a96aa3bSJed Brown   #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
4925d71ae5a4SJacob Faibussowitsch PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs)(PetscInt, PetscReal, const PetscReal[], PetscInt, PetscScalar *, void *), void **ctxs, Vec X, PetscReal diff[])
4926d71ae5a4SJacob Faibussowitsch {
49270a96aa3bSJed Brown   DM plex;
49280a96aa3bSJed Brown 
49290a96aa3bSJed Brown   PetscFunctionBegin;
49300a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49319566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49329566063dSJacob Faibussowitsch   PetscCall(DMComputeL2FieldDiff(plex, time, funcs, ctxs, X, diff));
49333ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49340a96aa3bSJed Brown }
49350a96aa3bSJed Brown 
49360a96aa3bSJed Brown   #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
4937d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
4938d71ae5a4SJacob Faibussowitsch {
49390a96aa3bSJed Brown   DM           plex;
49400a96aa3bSJed Brown   PetscSection section;
49410a96aa3bSJed Brown 
49420a96aa3bSJed Brown   PetscFunctionBegin;
49430a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49449566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49459566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(plex, &section));
49469566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dm, section));
49473ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49480a96aa3bSJed Brown }
49490a96aa3bSJed Brown 
49500a96aa3bSJed Brown   #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
4951d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
4952d71ae5a4SJacob Faibussowitsch {
49530a96aa3bSJed Brown   DM           plex;
49540a96aa3bSJed Brown   Mat          mat;
495579769bd5SJed Brown   Vec          bias;
49560a96aa3bSJed Brown   PetscSection section;
49570a96aa3bSJed Brown 
49580a96aa3bSJed Brown   PetscFunctionBegin;
49590a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49609566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49619566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(plex, &section, &mat, &bias));
49629566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm, section, mat, bias));
49633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49640a96aa3bSJed Brown }
49650a96aa3bSJed Brown 
49660a96aa3bSJed Brown   #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
4967d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
4968d71ae5a4SJacob Faibussowitsch {
49690a96aa3bSJed Brown   DM plex;
49700a96aa3bSJed Brown 
49710a96aa3bSJed Brown   PetscFunctionBegin;
49720a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
49739566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
49749566063dSJacob Faibussowitsch   PetscCall(DMGetDimPoints(plex, dim, cStart, cEnd));
49753ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49760a96aa3bSJed Brown }
49770a96aa3bSJed Brown 
49780a96aa3bSJed Brown   /* Need to forward declare */
49790a96aa3bSJed Brown   #define DMInitialize_pforest _append_pforest(DMInitialize)
49800a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
49810a96aa3bSJed Brown 
49820a96aa3bSJed Brown   #define DMClone_pforest _append_pforest(DMClone)
4983d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
4984d71ae5a4SJacob Faibussowitsch {
49850a96aa3bSJed Brown   PetscFunctionBegin;
49869566063dSJacob Faibussowitsch   PetscCall(DMClone_Forest(dm, newdm));
49879566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(*newdm));
49883ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
49890a96aa3bSJed Brown }
49900a96aa3bSJed Brown 
49910a96aa3bSJed Brown   #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
4992d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
4993d71ae5a4SJacob Faibussowitsch {
49940a96aa3bSJed Brown   DM_Forest         *forest;
49950a96aa3bSJed Brown   DM_Forest_pforest *pforest;
49960a96aa3bSJed Brown   PetscInt           overlap;
49970a96aa3bSJed Brown 
49980a96aa3bSJed Brown   PetscFunctionBegin;
49999566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
50000a96aa3bSJed Brown   forest  = (DM_Forest *)dm->data;
50010a96aa3bSJed Brown   pforest = (DM_Forest_pforest *)forest->data;
50020a96aa3bSJed Brown   *cStart = 0;
50039566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
50040a96aa3bSJed Brown   if (overlap && pforest->ghost) {
50050a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
50060a96aa3bSJed Brown   } else {
50070a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
50080a96aa3bSJed Brown   }
50093ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50100a96aa3bSJed Brown }
50110a96aa3bSJed Brown 
50120a96aa3bSJed Brown   #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
5013d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
5014d71ae5a4SJacob Faibussowitsch {
50150a96aa3bSJed Brown   DM_Forest         *forest;
50160a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50170a96aa3bSJed Brown   PetscMPIInt        rank;
50180a96aa3bSJed Brown   PetscInt           overlap;
50190a96aa3bSJed Brown   PetscInt           cStart, cEnd, cLocalStart, cLocalEnd;
50200a96aa3bSJed Brown   PetscInt           nRoots, nLeaves, *mine = NULL;
50210a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
50220a96aa3bSJed Brown   PetscSF            sf;
50230a96aa3bSJed Brown 
50240a96aa3bSJed Brown   PetscFunctionBegin;
50259566063dSJacob Faibussowitsch   PetscCall(DMForestGetCellChart(dm, &cStart, &cEnd));
50260a96aa3bSJed Brown   forest      = (DM_Forest *)dm->data;
50270a96aa3bSJed Brown   pforest     = (DM_Forest_pforest *)forest->data;
50280a96aa3bSJed Brown   nRoots      = cEnd - cStart;
50290a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
50300a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
50310a96aa3bSJed Brown   nLeaves     = 0;
50329566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm, &overlap));
50339566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm), &rank));
50340a96aa3bSJed Brown   if (overlap && pforest->ghost) {
50350a96aa3bSJed Brown     PetscSFNode      *mirror;
50360a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
50370a96aa3bSJed Brown     PetscInt          nMirror, nGhostPre, nSelf, q;
50380a96aa3bSJed Brown     void            **mirrorPtrs;
50390a96aa3bSJed Brown 
50400a96aa3bSJed Brown     nMirror   = (PetscInt)pforest->ghost->mirrors.elem_count;
50410a96aa3bSJed Brown     nSelf     = cLocalEnd - cLocalStart;
50420a96aa3bSJed Brown     nLeaves   = nRoots - nSelf;
50430a96aa3bSJed Brown     nGhostPre = (PetscInt)pforest->ghost->proc_offsets[rank];
50449566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &mine));
50459566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves, &remote));
50469566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nMirror, &mirror, nMirror, &mirrorPtrs));
50470a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t *)pforest->ghost->mirrors.array;
50480a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
5049*f4f49eeaSPierre Jolivet       p4est_quadrant_t *mir = &mirror_array[q];
50500a96aa3bSJed Brown 
50510a96aa3bSJed Brown       mirror[q].rank  = rank;
50520a96aa3bSJed Brown       mirror[q].index = (PetscInt)mir->p.piggy3.local_num + cLocalStart;
5053*f4f49eeaSPierre Jolivet       mirrorPtrs[q]   = (void *)&mirror[q];
50540a96aa3bSJed Brown     }
5055792fecdfSBarry Smith     PetscCallP4est(p4est_ghost_exchange_custom, (pforest->forest, pforest->ghost, sizeof(PetscSFNode), mirrorPtrs, remote));
50569566063dSJacob Faibussowitsch     PetscCall(PetscFree2(mirror, mirrorPtrs));
50570a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
50580a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
50590a96aa3bSJed Brown   }
50609566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm), &sf));
50619566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf, nRoots, nLeaves, mine, PETSC_OWN_POINTER, remote, PETSC_OWN_POINTER));
50620a96aa3bSJed Brown   *cellSF = sf;
50633ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50640a96aa3bSJed Brown }
50650a96aa3bSJed Brown 
5066d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS *ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void *), void **setup_ctx)
5067d71ae5a4SJacob Faibussowitsch {
50680a96aa3bSJed Brown   DM plex;
50690a96aa3bSJed Brown 
50700a96aa3bSJed Brown   PetscFunctionBegin;
50719566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
5072e4d5475eSStefano Zampini   PetscCall(DMCopyAuxiliaryVec(dm, plex));
50739566063dSJacob Faibussowitsch   PetscCall(DMCreateNeumannOverlap_Plex(plex, ovl, J, setup, setup_ctx));
5074e4d5475eSStefano Zampini   PetscCall(DMClearAuxiliaryVec(plex));
50750a96aa3bSJed Brown   if (!*setup) {
50769566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
507748a46eb9SPierre Jolivet     if (*setup) PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
50780a96aa3bSJed Brown   }
50793ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
50800a96aa3bSJed Brown }
50810a96aa3bSJed Brown 
5082907a3e9cSStefano Zampini   #define DMCreateDomainDecomposition_pforest _append_pforest(DMCreateDomainDecomposition)
5083907a3e9cSStefano Zampini static PetscErrorCode DMCreateDomainDecomposition_pforest(DM dm, PetscInt *nsub, char ***names, IS **innerises, IS **outerises, DM **dms)
5084907a3e9cSStefano Zampini {
5085907a3e9cSStefano Zampini   DM plex;
5086907a3e9cSStefano Zampini 
5087907a3e9cSStefano Zampini   PetscFunctionBegin;
5088907a3e9cSStefano Zampini   PetscCall(DMPforestGetPlex(dm, &plex));
5089e4d5475eSStefano Zampini   PetscCall(DMCopyAuxiliaryVec(dm, plex));
5090907a3e9cSStefano Zampini   PetscCall(DMCreateDomainDecomposition(plex, nsub, names, innerises, outerises, dms));
5091e4d5475eSStefano Zampini   PetscCall(DMClearAuxiliaryVec(plex));
5092907a3e9cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
5093907a3e9cSStefano Zampini }
5094907a3e9cSStefano Zampini 
5095907a3e9cSStefano Zampini   #define DMCreateDomainDecompositionScatters_pforest _append_pforest(DMCreateDomainDecompositionScatters)
5096907a3e9cSStefano Zampini static PetscErrorCode DMCreateDomainDecompositionScatters_pforest(DM dm, PetscInt n, DM *subdms, VecScatter **iscat, VecScatter **oscat, VecScatter **lscat)
5097907a3e9cSStefano Zampini {
5098907a3e9cSStefano Zampini   DM plex;
5099907a3e9cSStefano Zampini 
5100907a3e9cSStefano Zampini   PetscFunctionBegin;
5101907a3e9cSStefano Zampini   PetscCall(DMPforestGetPlex(dm, &plex));
5102e4d5475eSStefano Zampini   PetscCall(DMCopyAuxiliaryVec(dm, plex));
5103907a3e9cSStefano Zampini   PetscCall(DMCreateDomainDecompositionScatters(plex, n, subdms, iscat, oscat, lscat));
5104907a3e9cSStefano Zampini   PetscFunctionReturn(PETSC_SUCCESS);
5105907a3e9cSStefano Zampini }
5106907a3e9cSStefano Zampini 
5107d71ae5a4SJacob Faibussowitsch static PetscErrorCode DMInitialize_pforest(DM dm)
5108d71ae5a4SJacob Faibussowitsch {
51090a96aa3bSJed Brown   PetscFunctionBegin;
51100a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
51110a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
51120a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
51130a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
51140a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
51150a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
51160a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
51170a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
51180a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
51190a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
51200a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
51210a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
51220a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
51230a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
51240a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
51250a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
51260a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
51270a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
5128907a3e9cSStefano Zampini   dm->ops->createdomaindecomposition = DMCreateDomainDecomposition_pforest;
5129907a3e9cSStefano Zampini   dm->ops->createddscatters          = DMCreateDomainDecompositionScatters_pforest;
51300a96aa3bSJed Brown 
51319566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_plex_pforest) "_C", DMConvert_plex_pforest));
51329566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, PetscStringize(DMConvert_pforest_plex) "_C", DMConvert_pforest_plex));
51339566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMCreateNeumannOverlap_C", DMCreateNeumannOverlap_pforest));
51349566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm, "DMPlexGetOverlap_C", DMForestGetPartitionOverlap));
51353ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51360a96aa3bSJed Brown }
51370a96aa3bSJed Brown 
51380a96aa3bSJed Brown   #define DMCreate_pforest _append_pforest(DMCreate)
5139d71ae5a4SJacob Faibussowitsch PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
5140d71ae5a4SJacob Faibussowitsch {
51410a96aa3bSJed Brown   DM_Forest         *forest;
51420a96aa3bSJed Brown   DM_Forest_pforest *pforest;
51430a96aa3bSJed Brown 
51440a96aa3bSJed Brown   PetscFunctionBegin;
51459566063dSJacob Faibussowitsch   PetscCall(PetscP4estInitialize());
51469566063dSJacob Faibussowitsch   PetscCall(DMCreate_Forest(dm));
51479566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(dm));
51489566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm, P4EST_DIM));
51490a96aa3bSJed Brown 
51500a96aa3bSJed Brown   /* set forest defaults */
51519566063dSJacob Faibussowitsch   PetscCall(DMForestSetTopology(dm, "unit"));
51529566063dSJacob Faibussowitsch   PetscCall(DMForestSetMinimumRefinement(dm, 0));
51539566063dSJacob Faibussowitsch   PetscCall(DMForestSetInitialRefinement(dm, 0));
51549566063dSJacob Faibussowitsch   PetscCall(DMForestSetMaximumRefinement(dm, P4EST_QMAXLEVEL));
51559566063dSJacob Faibussowitsch   PetscCall(DMForestSetGradeFactor(dm, 2));
51569566063dSJacob Faibussowitsch   PetscCall(DMForestSetAdjacencyDimension(dm, 0));
51579566063dSJacob Faibussowitsch   PetscCall(DMForestSetPartitionOverlap(dm, 0));
51580a96aa3bSJed Brown 
51590a96aa3bSJed Brown   /* create p4est data */
51604dfa11a4SJacob Faibussowitsch   PetscCall(PetscNew(&pforest));
51610a96aa3bSJed Brown 
51620a96aa3bSJed Brown   forest                            = (DM_Forest *)dm->data;
51630a96aa3bSJed Brown   forest->data                      = pforest;
51640a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
51650a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
51660a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
51670a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
51680a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
51690a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
51700a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
51710a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
51720a96aa3bSJed Brown   pforest->topo                     = NULL;
51730a96aa3bSJed Brown   pforest->forest                   = NULL;
51740a96aa3bSJed Brown   pforest->ghost                    = NULL;
51750a96aa3bSJed Brown   pforest->lnodes                   = NULL;
51760a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
51770a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
51780a96aa3bSJed Brown   pforest->cLocalStart              = -1;
51790a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
51800a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
51810a96aa3bSJed Brown   pforest->ghostName                = NULL;
51823ba16761SJacob Faibussowitsch   PetscFunctionReturn(PETSC_SUCCESS);
51830a96aa3bSJed Brown }
51840a96aa3bSJed Brown 
51850a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5186