xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 1baa6e3354bfe224b33a0c158f482508792a8a6e)
10a96aa3bSJed Brown #include <petscds.h>
20a96aa3bSJed Brown #include <petsc/private/dmimpl.h>
30a96aa3bSJed Brown #include <petsc/private/dmforestimpl.h>
40a96aa3bSJed Brown #include <petsc/private/dmpleximpl.h>
50a96aa3bSJed Brown #include <petsc/private/dmlabelimpl.h>
60a96aa3bSJed Brown #include <petsc/private/viewerimpl.h>
70a96aa3bSJed Brown #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h>
80a96aa3bSJed Brown #include "petsc_p4est_package.h"
90a96aa3bSJed Brown 
100a96aa3bSJed Brown #if defined(PETSC_HAVE_P4EST)
110a96aa3bSJed Brown 
120a96aa3bSJed Brown #if !defined(P4_TO_P8)
130a96aa3bSJed Brown #include <p4est.h>
140a96aa3bSJed Brown #include <p4est_extended.h>
150a96aa3bSJed Brown #include <p4est_geometry.h>
160a96aa3bSJed Brown #include <p4est_ghost.h>
170a96aa3bSJed Brown #include <p4est_lnodes.h>
180a96aa3bSJed Brown #include <p4est_vtk.h>
190a96aa3bSJed Brown #include <p4est_plex.h>
200a96aa3bSJed Brown #include <p4est_bits.h>
210a96aa3bSJed Brown #include <p4est_algorithms.h>
220a96aa3bSJed Brown #else
230a96aa3bSJed Brown #include <p8est.h>
240a96aa3bSJed Brown #include <p8est_extended.h>
250a96aa3bSJed Brown #include <p8est_geometry.h>
260a96aa3bSJed Brown #include <p8est_ghost.h>
270a96aa3bSJed Brown #include <p8est_lnodes.h>
280a96aa3bSJed Brown #include <p8est_vtk.h>
290a96aa3bSJed Brown #include <p8est_plex.h>
300a96aa3bSJed Brown #include <p8est_bits.h>
310a96aa3bSJed Brown #include <p8est_algorithms.h>
320a96aa3bSJed Brown #endif
330a96aa3bSJed Brown 
340a96aa3bSJed Brown typedef enum {PATTERN_HASH,PATTERN_FRACTAL,PATTERN_CORNER,PATTERN_CENTER,PATTERN_COUNT} DMRefinePattern;
350a96aa3bSJed Brown static const char *DMRefinePatternName[PATTERN_COUNT] = {"hash","fractal","corner","center"};
360a96aa3bSJed Brown 
370a96aa3bSJed Brown typedef struct _DMRefinePatternCtx
380a96aa3bSJed Brown {
390a96aa3bSJed Brown   PetscInt       corner;
400a96aa3bSJed Brown   PetscBool      fractal[P4EST_CHILDREN];
410a96aa3bSJed Brown   PetscReal      hashLikelihood;
420a96aa3bSJed Brown   PetscInt       maxLevel;
430a96aa3bSJed Brown   p4est_refine_t refine_fn;
440a96aa3bSJed Brown }
450a96aa3bSJed Brown DMRefinePatternCtx;
460a96aa3bSJed Brown 
470a96aa3bSJed Brown static int DMRefinePattern_Corner(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
480a96aa3bSJed Brown {
490a96aa3bSJed Brown   p4est_quadrant_t   root, rootcorner;
500a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
510a96aa3bSJed Brown 
520a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
530a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
540a96aa3bSJed Brown 
550a96aa3bSJed Brown   root.x = root.y = 0;
560a96aa3bSJed Brown #if defined(P4_TO_P8)
570a96aa3bSJed Brown   root.z = 0;
580a96aa3bSJed Brown #endif
590a96aa3bSJed Brown   root.level = 0;
600a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&root,&rootcorner,ctx->corner,quadrant->level);
610a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant,&rootcorner)) return 1;
620a96aa3bSJed Brown   return 0;
630a96aa3bSJed Brown }
640a96aa3bSJed Brown 
650a96aa3bSJed Brown static int DMRefinePattern_Center(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
660a96aa3bSJed Brown {
670a96aa3bSJed Brown   int                cid;
680a96aa3bSJed Brown   p4est_quadrant_t   ancestor, ancestorcorner;
690a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
700a96aa3bSJed Brown 
710a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
720a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
730a96aa3bSJed Brown   if (quadrant->level <= 1) return 1;
740a96aa3bSJed Brown 
750a96aa3bSJed Brown   p4est_quadrant_ancestor(quadrant,1,&ancestor);
760a96aa3bSJed Brown   cid = p4est_quadrant_child_id(&ancestor);
770a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&ancestor,&ancestorcorner,P4EST_CHILDREN - 1 - cid,quadrant->level);
780a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant,&ancestorcorner)) return 1;
790a96aa3bSJed Brown   return 0;
800a96aa3bSJed Brown }
810a96aa3bSJed Brown 
820a96aa3bSJed Brown static int DMRefinePattern_Fractal(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
830a96aa3bSJed Brown {
840a96aa3bSJed Brown   int                cid;
850a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
860a96aa3bSJed Brown 
870a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
880a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
890a96aa3bSJed Brown   if (!quadrant->level) return 1;
900a96aa3bSJed Brown   cid = p4est_quadrant_child_id(quadrant);
910a96aa3bSJed Brown   if (ctx->fractal[cid ^ ((int) (quadrant->level % P4EST_CHILDREN))]) return 1;
920a96aa3bSJed Brown   return 0;
930a96aa3bSJed Brown }
940a96aa3bSJed Brown 
950a96aa3bSJed Brown /* simplified from MurmurHash3 by Austin Appleby */
960a96aa3bSJed Brown #define DMPROT32(x, y) ((x << y) | (x >> (32 - y)))
970a96aa3bSJed Brown static uint32_t DMPforestHash(const uint32_t *blocks, uint32_t nblocks)
980a96aa3bSJed Brown {
990a96aa3bSJed Brown   uint32_t c1   = 0xcc9e2d51;
1000a96aa3bSJed Brown   uint32_t c2   = 0x1b873593;
1010a96aa3bSJed Brown   uint32_t r1   = 15;
1020a96aa3bSJed Brown   uint32_t r2   = 13;
1030a96aa3bSJed Brown   uint32_t m    = 5;
1040a96aa3bSJed Brown   uint32_t n    = 0xe6546b64;
1050a96aa3bSJed Brown   uint32_t hash = 0;
1060a96aa3bSJed Brown   int      len  = nblocks * 4;
1070a96aa3bSJed Brown   uint32_t i;
1080a96aa3bSJed Brown 
1090a96aa3bSJed Brown   for (i = 0; i < nblocks; i++) {
1100a96aa3bSJed Brown     uint32_t k;
1110a96aa3bSJed Brown 
1120a96aa3bSJed Brown     k  = blocks[i];
1130a96aa3bSJed Brown     k *= c1;
1140a96aa3bSJed Brown     k  = DMPROT32(k, r1);
1150a96aa3bSJed Brown     k *= c2;
1160a96aa3bSJed Brown 
1170a96aa3bSJed Brown     hash ^= k;
1180a96aa3bSJed Brown     hash  = DMPROT32(hash, r2) * m + n;
1190a96aa3bSJed Brown   }
1200a96aa3bSJed Brown 
1210a96aa3bSJed Brown   hash ^= len;
1220a96aa3bSJed Brown   hash ^= (hash >> 16);
1230a96aa3bSJed Brown   hash *= 0x85ebca6b;
1240a96aa3bSJed Brown   hash ^= (hash >> 13);
1250a96aa3bSJed Brown   hash *= 0xc2b2ae35;
1260a96aa3bSJed Brown   hash ^= (hash >> 16);
1270a96aa3bSJed Brown 
1280a96aa3bSJed Brown   return hash;
1290a96aa3bSJed Brown }
1300a96aa3bSJed Brown 
1310a96aa3bSJed Brown #if defined(UINT32_MAX)
1320a96aa3bSJed Brown #define DMP4EST_HASH_MAX UINT32_MAX
1330a96aa3bSJed Brown #else
1340a96aa3bSJed Brown #define DMP4EST_HASH_MAX ((uint32_t) 0xffffffff)
1350a96aa3bSJed Brown #endif
1360a96aa3bSJed Brown 
1370a96aa3bSJed Brown static int DMRefinePattern_Hash(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
1380a96aa3bSJed Brown {
1390a96aa3bSJed Brown   uint32_t           data[5];
1400a96aa3bSJed Brown   uint32_t           result;
1410a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
1420a96aa3bSJed Brown 
1430a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
1440a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
1450a96aa3bSJed Brown   data[0] = ((uint32_t) quadrant->level) << 24;
1460a96aa3bSJed Brown   data[1] = (uint32_t) which_tree;
1470a96aa3bSJed Brown   data[2] = (uint32_t) quadrant->x;
1480a96aa3bSJed Brown   data[3] = (uint32_t) quadrant->y;
1490a96aa3bSJed Brown #if defined(P4_TO_P8)
1500a96aa3bSJed Brown   data[4] = (uint32_t) quadrant->z;
1510a96aa3bSJed Brown #endif
1520a96aa3bSJed Brown 
1530a96aa3bSJed Brown   result = DMPforestHash(data,2+P4EST_DIM);
1540a96aa3bSJed Brown   if (((double) result / (double) DMP4EST_HASH_MAX) < ctx->hashLikelihood) return 1;
1550a96aa3bSJed Brown   return 0;
1560a96aa3bSJed Brown }
1570a96aa3bSJed Brown 
1580a96aa3bSJed Brown #define DMConvert_pforest_plex _infix_pforest(DMConvert,_plex)
1590a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM,DMType,DM*);
1600a96aa3bSJed Brown 
1610a96aa3bSJed Brown #define DMFTopology_pforest _append_pforest(DMFTopology)
1620a96aa3bSJed Brown typedef struct {
1630a96aa3bSJed Brown   PetscInt             refct;
1640a96aa3bSJed Brown   p4est_connectivity_t *conn;
1650a96aa3bSJed Brown   p4est_geometry_t     *geom;
1660a96aa3bSJed Brown   PetscInt             *tree_face_to_uniq; /* p4est does not explicitly enumerate facets, but we must to keep track of labels */
1670a96aa3bSJed Brown } DMFTopology_pforest;
1680a96aa3bSJed Brown 
1690a96aa3bSJed Brown #define DM_Forest_pforest _append_pforest(DM_Forest)
1700a96aa3bSJed Brown typedef struct {
1710a96aa3bSJed Brown   DMFTopology_pforest *topo;
1720a96aa3bSJed Brown   p4est_t             *forest;
1730a96aa3bSJed Brown   p4est_ghost_t       *ghost;
1740a96aa3bSJed Brown   p4est_lnodes_t      *lnodes;
1750a96aa3bSJed Brown   PetscBool           partition_for_coarsening;
1760a96aa3bSJed Brown   PetscBool           coarsen_hierarchy;
1770a96aa3bSJed Brown   PetscBool           labelsFinalized;
1780a96aa3bSJed Brown   PetscBool           adaptivitySuccess;
1790a96aa3bSJed Brown   PetscInt            cLocalStart;
1800a96aa3bSJed Brown   PetscInt            cLocalEnd;
1810a96aa3bSJed Brown   DM                  plex;
1820a96aa3bSJed Brown   char                *ghostName;
1830a96aa3bSJed Brown   PetscSF             pointAdaptToSelfSF;
1840a96aa3bSJed Brown   PetscSF             pointSelfToAdaptSF;
1850a96aa3bSJed Brown   PetscInt            *pointAdaptToSelfCids;
1860a96aa3bSJed Brown   PetscInt            *pointSelfToAdaptCids;
1870a96aa3bSJed Brown } DM_Forest_pforest;
1880a96aa3bSJed Brown 
1890a96aa3bSJed Brown #define DM_Forest_geometry_pforest _append_pforest(DM_Forest_geometry)
1900a96aa3bSJed Brown typedef struct {
1910a96aa3bSJed Brown   DM base;
1920a96aa3bSJed Brown   PetscErrorCode   (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void*);
1930a96aa3bSJed Brown   void             *mapCtx;
1940a96aa3bSJed Brown   PetscInt         coordDim;
1950a96aa3bSJed Brown   p4est_geometry_t *inner;
1960a96aa3bSJed Brown }
1970a96aa3bSJed Brown DM_Forest_geometry_pforest;
1980a96aa3bSJed Brown 
1990a96aa3bSJed Brown #define GeometryMapping_pforest _append_pforest(GeometryMapping)
2000a96aa3bSJed Brown static void GeometryMapping_pforest(p4est_geometry_t *geom, p4est_topidx_t which_tree, const double abc[3], double xyz[3])
2010a96aa3bSJed Brown {
2020a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user;
2030a96aa3bSJed Brown   PetscReal                  PetscABC[3]   = {0.};
2040a96aa3bSJed Brown   PetscReal                  PetscXYZ[3]   = {0.};
2050a96aa3bSJed Brown   PetscInt                   i, d = PetscMin(3,geom_pforest->coordDim);
2060a96aa3bSJed Brown   double                     ABC[3];
2070a96aa3bSJed Brown   PetscErrorCode             ierr;
2080a96aa3bSJed Brown 
2090a96aa3bSJed Brown   (geom_pforest->inner->X)(geom_pforest->inner,which_tree,abc,ABC);
2100a96aa3bSJed Brown 
2110a96aa3bSJed Brown   for (i = 0; i < d; i++) PetscABC[i] = ABC[i];
2120a96aa3bSJed Brown   ierr = (geom_pforest->map)(geom_pforest->base,(PetscInt) which_tree,geom_pforest->coordDim,PetscABC,PetscXYZ,geom_pforest->mapCtx);PETSC_P4EST_ASSERT(!ierr);
2130a96aa3bSJed Brown   for (i = 0; i < d; i++) xyz[i] = PetscXYZ[i];
2140a96aa3bSJed Brown }
2150a96aa3bSJed Brown 
2160a96aa3bSJed Brown #define GeometryDestroy_pforest _append_pforest(GeometryDestroy)
2170a96aa3bSJed Brown static void GeometryDestroy_pforest(p4est_geometry_t *geom)
2180a96aa3bSJed Brown {
2190a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user;
2200a96aa3bSJed Brown   PetscErrorCode             ierr;
2210a96aa3bSJed Brown 
2220a96aa3bSJed Brown   p4est_geometry_destroy(geom_pforest->inner);
2230a96aa3bSJed Brown   ierr = PetscFree(geom->user);PETSC_P4EST_ASSERT(!ierr);
2240a96aa3bSJed Brown   ierr = PetscFree(geom);PETSC_P4EST_ASSERT(!ierr);
2250a96aa3bSJed Brown }
2260a96aa3bSJed Brown 
2270a96aa3bSJed Brown #define DMFTopologyDestroy_pforest _append_pforest(DMFTopologyDestroy)
2280a96aa3bSJed Brown static PetscErrorCode DMFTopologyDestroy_pforest(DMFTopology_pforest **topo)
2290a96aa3bSJed Brown {
2300a96aa3bSJed Brown   PetscFunctionBegin;
2310a96aa3bSJed Brown   if (!(*topo)) PetscFunctionReturn(0);
2320a96aa3bSJed Brown   if (--((*topo)->refct) > 0) {
2330a96aa3bSJed Brown     *topo = NULL;
2340a96aa3bSJed Brown     PetscFunctionReturn(0);
2350a96aa3bSJed Brown   }
2360a96aa3bSJed Brown   if ((*topo)->geom) PetscStackCallP4est(p4est_geometry_destroy,((*topo)->geom));
2370a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,((*topo)->conn));
2389566063dSJacob Faibussowitsch   PetscCall(PetscFree((*topo)->tree_face_to_uniq));
2399566063dSJacob Faibussowitsch   PetscCall(PetscFree(*topo));
2400a96aa3bSJed Brown   *topo = NULL;
2410a96aa3bSJed Brown   PetscFunctionReturn(0);
2420a96aa3bSJed Brown }
2430a96aa3bSJed Brown 
2440a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t*,PetscInt**);
2450a96aa3bSJed Brown 
2460a96aa3bSJed Brown #define DMFTopologyCreateBrick_pforest _append_pforest(DMFTopologyCreateBrick)
2470a96aa3bSJed Brown static PetscErrorCode DMFTopologyCreateBrick_pforest(DM dm,PetscInt N[], PetscInt P[], PetscReal B[],DMFTopology_pforest **topo, PetscBool useMorton)
2480a96aa3bSJed Brown {
2490a96aa3bSJed Brown   double         *vertices;
2500a96aa3bSJed Brown   PetscInt       i, numVerts;
2510a96aa3bSJed Brown 
2520a96aa3bSJed Brown   PetscFunctionBegin;
25328b400f6SJacob Faibussowitsch   PetscCheck(useMorton,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Lexicographic ordering not implemented yet");
2549566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(dm,topo));
2550a96aa3bSJed Brown 
2560a96aa3bSJed Brown   (*topo)->refct = 1;
2570a96aa3bSJed Brown #if !defined(P4_TO_P8)
2580a96aa3bSJed Brown   PetscStackCallP4estReturn((*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));
2590a96aa3bSJed Brown #else
2600a96aa3bSJed Brown   PetscStackCallP4estReturn((*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));
2610a96aa3bSJed Brown #endif
2620a96aa3bSJed Brown   numVerts = (*topo)->conn->num_vertices;
2630a96aa3bSJed Brown   vertices = (*topo)->conn->vertices;
2640a96aa3bSJed Brown   for (i = 0; i < 3 * numVerts; i++) {
2650a96aa3bSJed Brown     PetscInt j = i % 3;
2660a96aa3bSJed Brown 
2670a96aa3bSJed Brown     vertices[i] = B[2 * j] + (vertices[i]/N[j]) * (B[2 * j + 1] - B[2 * j]);
2680a96aa3bSJed Brown   }
2690a96aa3bSJed Brown   (*topo)->geom = NULL;
2709566063dSJacob Faibussowitsch   PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq));
2710a96aa3bSJed Brown   PetscFunctionReturn(0);
2720a96aa3bSJed Brown }
2730a96aa3bSJed Brown 
2740a96aa3bSJed Brown #define DMFTopologyCreate_pforest _append_pforest(DMFTopologyCreate)
2750a96aa3bSJed Brown static PetscErrorCode DMFTopologyCreate_pforest(DM dm, DMForestTopology topologyName, DMFTopology_pforest **topo)
2760a96aa3bSJed Brown {
2770a96aa3bSJed Brown   const char     *name = (const char*) topologyName;
2780a96aa3bSJed Brown   const char     *prefix;
2790a96aa3bSJed Brown   PetscBool      isBrick, isShell, isSphere, isMoebius;
2800a96aa3bSJed Brown 
2810a96aa3bSJed Brown   PetscFunctionBegin;
2820a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2830a96aa3bSJed Brown   PetscValidCharPointer(name,2);
2840a96aa3bSJed Brown   PetscValidPointer(topo,3);
2859566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"brick",&isBrick));
2869566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"shell",&isShell));
2879566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"sphere",&isSphere));
2889566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"moebius",&isMoebius));
2899566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
2900a96aa3bSJed Brown   if (isBrick) {
2910a96aa3bSJed Brown     PetscBool flgN, flgP, flgM, flgB, useMorton = PETSC_TRUE, periodic = PETSC_FALSE;
2920a96aa3bSJed Brown     PetscInt  N[3] = {2,2,2}, P[3] = {0,0,0}, nretN = P4EST_DIM, nretP = P4EST_DIM, nretB = 2 * P4EST_DIM, i;
2930a96aa3bSJed Brown     PetscReal B[6] = {0.0,1.0,0.0,1.0,0.0,1.0};
2940a96aa3bSJed Brown 
2950a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
2969566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_size",N,&nretN,&flgN));
2979566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_periodicity",P,&nretP,&flgP));
2989566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_bounds",B,&nretB,&flgB));
2999566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_use_morton_curve",&useMorton,&flgM));
3001dca8a05SBarry 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);
3011dca8a05SBarry 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);
3021dca8a05SBarry 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);
3030a96aa3bSJed Brown     }
3040a96aa3bSJed Brown     for (i = 0; i < P4EST_DIM; i++) {
3050a96aa3bSJed Brown       P[i]  = (P[i] ? DM_BOUNDARY_PERIODIC : DM_BOUNDARY_NONE);
3060a96aa3bSJed Brown       periodic = (PetscBool)(P[i] || periodic);
3070a96aa3bSJed Brown       if (!flgB) B[2 * i + 1] = N[i];
3080a96aa3bSJed Brown     }
3099566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,B,topo,useMorton));
3100a96aa3bSJed Brown     /* the maxCell trick is not robust enough, localize on all cells if periodic */
3119566063dSJacob Faibussowitsch     PetscCall(DMSetPeriodicity(dm,periodic,NULL,NULL,NULL));
3120a96aa3bSJed Brown   } else {
3139566063dSJacob Faibussowitsch     PetscCall(PetscNewLog(dm,topo));
3140a96aa3bSJed Brown 
3150a96aa3bSJed Brown     (*topo)->refct = 1;
3160a96aa3bSJed Brown     PetscStackCallP4estReturn((*topo)->conn,p4est_connectivity_new_byname,(name));
3170a96aa3bSJed Brown     (*topo)->geom = NULL;
318*1baa6e33SBarry Smith     if (isMoebius) PetscCall(DMSetCoordinateDim(dm,3));
3190a96aa3bSJed Brown #if defined(P4_TO_P8)
3200a96aa3bSJed Brown     if (isShell) {
3210a96aa3bSJed Brown       PetscReal R2 = 1., R1 = .55;
3220a96aa3bSJed Brown 
3230a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3249566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_outer_radius",&R2,NULL));
3259566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_inner_radius",&R1,NULL));
3260a96aa3bSJed Brown       }
3270a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_shell,((*topo)->conn,R2,R1));
3280a96aa3bSJed Brown     } else if (isSphere) {
3290a96aa3bSJed Brown       PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856;
3300a96aa3bSJed Brown 
3310a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3329566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_outer_radius",&R2,NULL));
3339566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_inner_radius",&R1,NULL));
3349566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_core_radius",&R0,NULL));
3350a96aa3bSJed Brown       }
3360a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_sphere,((*topo)->conn,R2,R1,R0));
3370a96aa3bSJed Brown     }
3380a96aa3bSJed Brown #endif
3399566063dSJacob Faibussowitsch     PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq));
3400a96aa3bSJed Brown   }
3410a96aa3bSJed Brown   PetscFunctionReturn(0);
3420a96aa3bSJed Brown }
3430a96aa3bSJed Brown 
3440a96aa3bSJed Brown #define DMConvert_plex_pforest _append_pforest(DMConvert_plex)
3450a96aa3bSJed Brown static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest)
3460a96aa3bSJed Brown {
3470a96aa3bSJed Brown   MPI_Comm       comm;
3480a96aa3bSJed Brown   PetscBool      isPlex;
3490a96aa3bSJed Brown   PetscInt       dim;
3500a96aa3bSJed Brown   void           *ctx;
3510a96aa3bSJed Brown 
3520a96aa3bSJed Brown   PetscFunctionBegin;
3530a96aa3bSJed Brown 
3540a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3550a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
3569566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex));
35728b400f6SJacob Faibussowitsch   PetscCheck(isPlex,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPLEX,((PetscObject)dm)->type_name);
3589566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dim));
35963a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim);
3609566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm,pforest));
3619566063dSJacob Faibussowitsch   PetscCall(DMSetType(*pforest,DMPFOREST));
3629566063dSJacob Faibussowitsch   PetscCall(DMForestSetBaseDM(*pforest,dm));
3639566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dm,&ctx));
3649566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(*pforest,ctx));
3659566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm,*pforest));
3660a96aa3bSJed Brown   PetscFunctionReturn(0);
3670a96aa3bSJed Brown }
3680a96aa3bSJed Brown 
3690a96aa3bSJed Brown #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
3700a96aa3bSJed Brown static PetscErrorCode DMForestDestroy_pforest(DM dm)
3710a96aa3bSJed Brown {
3720a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
3730a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
3740a96aa3bSJed Brown 
3750a96aa3bSJed Brown   PetscFunctionBegin;
3760a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3770a96aa3bSJed Brown   if (pforest->lnodes) PetscStackCallP4est(p4est_lnodes_destroy,(pforest->lnodes));
3780a96aa3bSJed Brown   pforest->lnodes = NULL;
3790a96aa3bSJed Brown   if (pforest->ghost) PetscStackCallP4est(p4est_ghost_destroy,(pforest->ghost));
3800a96aa3bSJed Brown   pforest->ghost = NULL;
3810a96aa3bSJed Brown   if (pforest->forest) PetscStackCallP4est(p4est_destroy,(pforest->forest));
3820a96aa3bSJed Brown   pforest->forest = NULL;
3839566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&pforest->topo));
3849566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",NULL));
3859566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",NULL));
3862e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL));
3879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",NULL));
3882e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL));
3892e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL));
3909566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->ghostName));
3919566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&pforest->plex));
3929566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
3939566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
3949566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
3959566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
3969566063dSJacob Faibussowitsch   PetscCall(PetscFree(forest->data));
3970a96aa3bSJed Brown   PetscFunctionReturn(0);
3980a96aa3bSJed Brown }
3990a96aa3bSJed Brown 
4000a96aa3bSJed Brown #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
4010a96aa3bSJed Brown static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm)
4020a96aa3bSJed Brown {
4030a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4040a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest*) ((DM_Forest*) tdm->data)->data;
4050a96aa3bSJed Brown 
4060a96aa3bSJed Brown   PetscFunctionBegin;
4070a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
4089566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&(tpforest->topo)));
4090a96aa3bSJed Brown   tpforest->topo = pforest->topo;
4100a96aa3bSJed Brown   PetscFunctionReturn(0);
4110a96aa3bSJed Brown }
4120a96aa3bSJed Brown 
4130a96aa3bSJed Brown #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
4140a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM,p4est_connectivity_t**,PetscInt**);
4150a96aa3bSJed Brown 
4160a96aa3bSJed Brown typedef struct _PforestAdaptCtx
4170a96aa3bSJed Brown {
4180a96aa3bSJed Brown   PetscInt  maxLevel;
4190a96aa3bSJed Brown   PetscInt  minLevel;
4200a96aa3bSJed Brown   PetscInt  currLevel;
4210a96aa3bSJed Brown   PetscBool anyChange;
4220a96aa3bSJed Brown }
4230a96aa3bSJed Brown PforestAdaptCtx;
4240a96aa3bSJed Brown 
4250a96aa3bSJed Brown static int pforest_coarsen_currlevel(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4260a96aa3bSJed Brown {
4270a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx*) p4est->user_pointer;
4280a96aa3bSJed Brown   PetscInt        minLevel  = ctx->minLevel;
4290a96aa3bSJed Brown   PetscInt        currLevel = ctx->currLevel;
4300a96aa3bSJed Brown 
4310a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4320a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level == currLevel);
4330a96aa3bSJed Brown }
4340a96aa3bSJed Brown 
4350a96aa3bSJed Brown static int pforest_coarsen_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4360a96aa3bSJed Brown {
4370a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4380a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4390a96aa3bSJed Brown 
4400a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level > minLevel);
4410a96aa3bSJed Brown }
4420a96aa3bSJed Brown 
4430a96aa3bSJed Brown static int pforest_coarsen_flag_any(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4440a96aa3bSJed Brown {
4450a96aa3bSJed Brown   PetscInt        i;
4460a96aa3bSJed Brown   PetscBool       any      = PETSC_FALSE;
4470a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4480a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4490a96aa3bSJed Brown 
4500a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4510a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4520a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
4530a96aa3bSJed Brown       any = PETSC_FALSE;
4540a96aa3bSJed Brown       break;
4550a96aa3bSJed Brown     }
4560a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
4570a96aa3bSJed Brown       any = PETSC_TRUE;
4580a96aa3bSJed Brown       break;
4590a96aa3bSJed Brown     }
4600a96aa3bSJed Brown   }
4610a96aa3bSJed Brown   return any ? 1 : 0;
4620a96aa3bSJed Brown }
4630a96aa3bSJed Brown 
4640a96aa3bSJed Brown static int pforest_coarsen_flag_all(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4650a96aa3bSJed Brown {
4660a96aa3bSJed Brown   PetscInt        i;
4670a96aa3bSJed Brown   PetscBool       all      = PETSC_TRUE;
4680a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4690a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4700a96aa3bSJed Brown 
4710a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4720a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4730a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
4740a96aa3bSJed Brown       all = PETSC_FALSE;
4750a96aa3bSJed Brown       break;
4760a96aa3bSJed Brown     }
4770a96aa3bSJed Brown   }
4780a96aa3bSJed Brown   return all ? 1 : 0;
4790a96aa3bSJed Brown }
4800a96aa3bSJed Brown 
4810a96aa3bSJed Brown static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4820a96aa3bSJed Brown {
4830a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
4840a96aa3bSJed Brown }
4850a96aa3bSJed Brown 
4860a96aa3bSJed Brown static int pforest_refine_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4870a96aa3bSJed Brown {
4880a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4890a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
4900a96aa3bSJed Brown 
4910a96aa3bSJed Brown   return ((PetscInt) quadrant->level < maxLevel);
4920a96aa3bSJed Brown }
4930a96aa3bSJed Brown 
4940a96aa3bSJed Brown static int pforest_refine_flag(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4950a96aa3bSJed Brown {
4960a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4970a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
4980a96aa3bSJed Brown 
4990a96aa3bSJed Brown   if ((PetscInt) quadrant->level >= maxLevel) return 0;
5000a96aa3bSJed Brown 
5010a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
5020a96aa3bSJed Brown }
5030a96aa3bSJed Brown 
5040a96aa3bSJed Brown 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)
5050a96aa3bSJed Brown {
5060a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
5070a96aa3bSJed Brown   p4est_topidx_t t;
5080a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
5090a96aa3bSJed Brown 
5100a96aa3bSJed Brown   PetscFunctionBegin;
5110a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
5120a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t*) p4estFrom->trees->array)[t]);
5130a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t*) p4estTo->trees->array)[t]);
5140a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
5150a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
5160a96aa3bSJed Brown     PetscInt         numFrom    = (PetscInt) treeFrom->quadrants.elem_count;
5170a96aa3bSJed Brown     PetscInt         numTo      = (PetscInt) treeTo->quadrants.elem_count;
5180a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t*) treeFrom->quadrants.array;
5190a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t*) treeTo->quadrants.array;
5200a96aa3bSJed Brown     PetscInt         currentFrom, currentTo;
5210a96aa3bSJed Brown     PetscInt         treeOffsetFrom = (PetscInt) treeFrom->quadrants_offset;
5220a96aa3bSJed Brown     PetscInt         treeOffsetTo   = (PetscInt) treeTo->quadrants_offset;
5230a96aa3bSJed Brown     int              comp;
5240a96aa3bSJed Brown 
5250a96aa3bSJed Brown     PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(firstFrom,firstTo));
52628b400f6SJacob Faibussowitsch     PetscCheck(comp,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"non-matching partitions");
5270a96aa3bSJed Brown 
5280a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
5290a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
5300a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
5310a96aa3bSJed Brown 
5320a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
5330a96aa3bSJed Brown         if (toLeaves) {
5340a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5350a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
5360a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5370a96aa3bSJed Brown         }
5380a96aa3bSJed Brown         toFineLeaves++;
5390a96aa3bSJed Brown         currentFrom++;
5400a96aa3bSJed Brown         currentTo++;
5410a96aa3bSJed Brown       } else {
5420a96aa3bSJed Brown         int fromIsAncestor;
5430a96aa3bSJed Brown 
5440a96aa3bSJed Brown         PetscStackCallP4estReturn(fromIsAncestor,p4est_quadrant_is_ancestor,(quadFrom,quadTo));
5450a96aa3bSJed Brown         if (fromIsAncestor) {
5460a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5470a96aa3bSJed Brown 
5480a96aa3bSJed Brown           if (toLeaves) {
5490a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5500a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
5510a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5520a96aa3bSJed Brown           }
5530a96aa3bSJed Brown           toFineLeaves++;
5540a96aa3bSJed Brown           currentTo++;
5550a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadFrom,&lastDesc,quadTo->level));
5560a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadTo,&lastDesc));
5570a96aa3bSJed Brown           if (comp) currentFrom++;
5580a96aa3bSJed Brown         } else {
5590a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5600a96aa3bSJed Brown 
5610a96aa3bSJed Brown           if (fromLeaves) {
5620a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
5630a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
5640a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
5650a96aa3bSJed Brown           }
5660a96aa3bSJed Brown           fromFineLeaves++;
5670a96aa3bSJed Brown           currentFrom++;
5680a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadTo,&lastDesc,quadFrom->level));
5690a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadFrom,&lastDesc));
5700a96aa3bSJed Brown           if (comp) currentTo++;
5710a96aa3bSJed Brown         }
5720a96aa3bSJed Brown       }
5730a96aa3bSJed Brown     }
5740a96aa3bSJed Brown   }
5750a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
5760a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
5770a96aa3bSJed Brown   PetscFunctionReturn(0);
5780a96aa3bSJed Brown }
5790a96aa3bSJed Brown 
5800a96aa3bSJed Brown /* Compute the maximum level across all the trees */
5810a96aa3bSJed Brown static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev)
5820a96aa3bSJed Brown {
5830a96aa3bSJed Brown   p4est_topidx_t    t, flt, llt;
5840a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
5850a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
5860a96aa3bSJed Brown   PetscInt          maxlevelloc = 0;
5870a96aa3bSJed Brown   p4est_t           *p4est;
5880a96aa3bSJed Brown 
5890a96aa3bSJed Brown   PetscFunctionBegin;
59028b400f6SJacob Faibussowitsch   PetscCheck(pforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing DM_Forest_pforest");
59128b400f6SJacob Faibussowitsch   PetscCheck(pforest->forest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing p4est_t");
5920a96aa3bSJed Brown   p4est = pforest->forest;
5930a96aa3bSJed Brown   flt   = p4est->first_local_tree;
5940a96aa3bSJed Brown   llt   = p4est->last_local_tree;
5950a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
5960a96aa3bSJed Brown     p4est_tree_t *tree  = &(((p4est_tree_t*) p4est->trees->array)[t]);
5970a96aa3bSJed Brown     maxlevelloc = PetscMax((PetscInt)tree->maxlevel,maxlevelloc);
5980a96aa3bSJed Brown   }
5991c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&maxlevelloc,lev,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
6000a96aa3bSJed Brown   PetscFunctionReturn(0);
6010a96aa3bSJed Brown }
6020a96aa3bSJed Brown 
6030a96aa3bSJed Brown /* Puts identity in coarseToFine */
6040a96aa3bSJed Brown /* assumes a matching partition */
6050a96aa3bSJed Brown static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine)
6060a96aa3bSJed Brown {
6070a96aa3bSJed Brown   p4est_topidx_t flt, llt;
6080a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
6090a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
6100a96aa3bSJed Brown   PetscInt       *fromLeaves = NULL, *toLeaves = NULL;
6110a96aa3bSJed Brown   PetscSFNode    *fromRoots  = NULL, *toRoots = NULL;
6120a96aa3bSJed Brown 
6130a96aa3bSJed Brown   PetscFunctionBegin;
6140a96aa3bSJed Brown   flt  = p4estFrom->first_local_tree;
6150a96aa3bSJed Brown   llt  = p4estFrom->last_local_tree;
6169566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm,&fromCoarse));
6170a96aa3bSJed Brown   if (toCoarseFromFine) {
6189566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm,&toCoarse));
6190a96aa3bSJed Brown   }
6200a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
6210a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
6229566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,NULL,NULL,&numLeavesFrom,NULL,NULL));
6239566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo,&toLeaves));
6249566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo,&fromRoots));
6250a96aa3bSJed Brown   if (toCoarseFromFine) {
6269566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom,&fromLeaves));
6279566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom,&fromRoots));
6280a96aa3bSJed Brown   }
6299566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,toLeaves,fromRoots,&numLeavesFrom,fromLeaves,toRoots));
6300a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
6319566063dSJacob Faibussowitsch     PetscCall(PetscFree(toLeaves));
6329566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,NULL,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER));
633*1baa6e33SBarry Smith   } else PetscCall(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,toLeaves,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER));
6340a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
6350a96aa3bSJed Brown   if (toCoarseFromFine) {
6369566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(toCoarse,numRootsTo,numLeavesFrom,fromLeaves,PETSC_OWN_POINTER,toRoots,PETSC_OWN_POINTER));
6370a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
6380a96aa3bSJed Brown   }
6390a96aa3bSJed Brown   PetscFunctionReturn(0);
6400a96aa3bSJed Brown }
6410a96aa3bSJed Brown 
6420a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
6430a96aa3bSJed Brown static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB)
6440a96aa3bSJed Brown {
6450a96aa3bSJed Brown   p4est_quadrant_t * myCoarseStart = &(p4estA->global_first_position[rank]);
6460a96aa3bSJed Brown   p4est_quadrant_t * myCoarseEnd   = &(p4estA->global_first_position[rank+1]);
6470a96aa3bSJed Brown   p4est_quadrant_t * globalFirstB  = p4estB->global_first_position;
6480a96aa3bSJed Brown 
6490a96aa3bSJed Brown   PetscFunctionBegin;
6500a96aa3bSJed Brown   *startB = -1;
6510a96aa3bSJed Brown   *endB   = -1;
6520a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
6530a96aa3bSJed Brown     PetscInt lo, hi, guess;
6540a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
6550a96aa3bSJed Brown     lo    = 0;
6560a96aa3bSJed Brown     hi    = size;
6570a96aa3bSJed Brown     guess = rank;
6580a96aa3bSJed Brown     while (1) {
6590a96aa3bSJed Brown       int startCompMy, myCompEnd;
6600a96aa3bSJed Brown 
6610a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseStart));
6620a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseStart,&globalFirstB[guess+1]));
6630a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
6640a96aa3bSJed Brown         *startB = guess;
6650a96aa3bSJed Brown         break;
6660a96aa3bSJed Brown       } else if (startCompMy > 0) {  /* guess is to high */
6670a96aa3bSJed Brown         hi = guess;
6680a96aa3bSJed Brown       } else { /* guess is to low */
6690a96aa3bSJed Brown         lo = guess + 1;
6700a96aa3bSJed Brown       }
6710a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6720a96aa3bSJed Brown     }
6730a96aa3bSJed Brown     /* reset bounds, but not guess */
6740a96aa3bSJed Brown     lo = 0;
6750a96aa3bSJed Brown     hi = size;
6760a96aa3bSJed Brown     while (1) {
6770a96aa3bSJed Brown       int startCompMy, myCompEnd;
6780a96aa3bSJed Brown 
6790a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseEnd));
6800a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseEnd,&globalFirstB[guess+1]));
6810a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
6820a96aa3bSJed Brown         *endB = guess + 1;
6830a96aa3bSJed Brown         break;
6840a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
6850a96aa3bSJed Brown         hi = guess;
6860a96aa3bSJed Brown       } else { /* guess is to low */
6870a96aa3bSJed Brown         lo = guess + 1;
6880a96aa3bSJed Brown       }
6890a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6900a96aa3bSJed Brown     }
6910a96aa3bSJed Brown   }
6920a96aa3bSJed Brown   PetscFunctionReturn(0);
6930a96aa3bSJed Brown }
6940a96aa3bSJed Brown 
6950a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM,DM*);
6960a96aa3bSJed Brown 
6970a96aa3bSJed Brown #define DMSetUp_pforest _append_pforest(DMSetUp)
6980a96aa3bSJed Brown static PetscErrorCode DMSetUp_pforest(DM dm)
6990a96aa3bSJed Brown {
7000a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
7010a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
7020a96aa3bSJed Brown   DM                base, adaptFrom;
7030a96aa3bSJed Brown   DMForestTopology  topoName;
7040a96aa3bSJed Brown   PetscSF           preCoarseToFine = NULL, coarseToPreFine = NULL;
7050a96aa3bSJed Brown   PforestAdaptCtx   ctx;
7060a96aa3bSJed Brown 
7070a96aa3bSJed Brown   PetscFunctionBegin;
7080a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
7090a96aa3bSJed Brown   ctx.maxLevel  = 0;
7100a96aa3bSJed Brown   ctx.currLevel = 0;
7110a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
7120a96aa3bSJed Brown   /* sanity check */
7139566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm,&adaptFrom));
7149566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
7159566063dSJacob Faibussowitsch   PetscCall(DMForestGetTopology(dm,&topoName));
7161dca8a05SBarry 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");
7170a96aa3bSJed Brown 
7180a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
7190a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
7200a96aa3bSJed Brown     PetscBool         ispforest;
7210a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
7220a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
7230a96aa3bSJed Brown 
7249566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)adaptFrom,DMPFOREST,&ispforest));
72528b400f6SJacob Faibussowitsch     PetscCheck(ispforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Trying to adapt from %s, which is not %s",((PetscObject)adaptFrom)->type_name,DMPFOREST);
72628b400f6SJacob Faibussowitsch     PetscCheck(apforest->topo,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"The pre-adaptation forest must have a topology");
7279566063dSJacob Faibussowitsch     PetscCall(DMSetUp(adaptFrom));
7289566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm,&base));
7299566063dSJacob Faibussowitsch     PetscCall(DMForestGetTopology(dm,&topoName));
7300a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
7310a96aa3bSJed Brown     PetscBool isPlex, isDA;
7320a96aa3bSJed Brown 
7339566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)base,&topoName));
7349566063dSJacob Faibussowitsch     PetscCall(DMForestSetTopology(dm,topoName));
7359566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base,DMPLEX,&isPlex));
7369566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base,DMDA,&isDA));
7370a96aa3bSJed Brown     if (isPlex) {
7380a96aa3bSJed Brown       MPI_Comm             comm = PetscObjectComm((PetscObject)dm);
7390a96aa3bSJed Brown       PetscInt             depth;
7400a96aa3bSJed Brown       PetscMPIInt          size;
7410a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
7420a96aa3bSJed Brown       DMFTopology_pforest  *topo;
7430a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
7440a96aa3bSJed Brown 
7459566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepth(base,&depth));
7460a96aa3bSJed Brown       if (depth == 1) {
7470a96aa3bSJed Brown         DM connDM;
7480a96aa3bSJed Brown 
7499566063dSJacob Faibussowitsch         PetscCall(DMPlexInterpolate(base,&connDM));
7500a96aa3bSJed Brown         base = connDM;
7519566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm,base));
7529566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&connDM));
75363a3b9bcSJacob 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);
7549566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(comm,&size));
7550a96aa3bSJed Brown       if (size > 1) {
7560a96aa3bSJed Brown         DM      dmRedundant;
7570a96aa3bSJed Brown         PetscSF sf;
7580a96aa3bSJed Brown 
7599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetRedundantDM(base,&sf,&dmRedundant));
76028b400f6SJacob Faibussowitsch         PetscCheck(dmRedundant,comm,PETSC_ERR_PLIB,"Could not create redundant DM");
7619566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)dmRedundant,"_base_migration_sf",(PetscObject)sf));
7629566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&sf));
7630a96aa3bSJed Brown         base = dmRedundant;
7649566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm,base));
7659566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&dmRedundant));
7660a96aa3bSJed Brown       }
7679566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(base,NULL,"-dm_p4est_base_view"));
7689566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateConnectivity_pforest(base,&conn,&tree_face_to_uniq));
7699566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(dm,&topo));
7700a96aa3bSJed Brown       topo->refct = 1;
7710a96aa3bSJed Brown       topo->conn  = conn;
7720a96aa3bSJed Brown       topo->geom  = NULL;
7730a96aa3bSJed Brown       {
7740a96aa3bSJed Brown         PetscErrorCode (*map)(DM,PetscInt,PetscInt,const PetscReal[],PetscReal[],void*);
7750a96aa3bSJed Brown         void           *mapCtx;
7760a96aa3bSJed Brown 
7779566063dSJacob Faibussowitsch         PetscCall(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx));
7780a96aa3bSJed Brown         if (map) {
7790a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
7800a96aa3bSJed Brown           p4est_geometry_t           *geom;
7810a96aa3bSJed Brown 
7829566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom_pforest));
7839566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinateDim(dm,&geom_pforest->coordDim));
7840a96aa3bSJed Brown           geom_pforest->map    = map;
7850a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
7860a96aa3bSJed Brown           PetscStackCallP4estReturn(geom_pforest->inner,p4est_geometry_new_connectivity,(conn));
7879566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom));
7880a96aa3bSJed Brown           geom->name    = topoName;
7890a96aa3bSJed Brown           geom->user    = geom_pforest;
7900a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
7910a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
7920a96aa3bSJed Brown           topo->geom    = geom;
7930a96aa3bSJed Brown         }
7940a96aa3bSJed Brown       }
7950a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
7960a96aa3bSJed Brown       pforest->topo           = topo;
79728b400f6SJacob Faibussowitsch     } else PetscCheck(!isDA,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Not implemented yet");
7980a96aa3bSJed Brown #if 0
7990a96aa3bSJed Brown       PetscInt N[3], P[3];
8000a96aa3bSJed Brown 
8010a96aa3bSJed Brown       /* get the sizes, periodicities */
8020a96aa3bSJed Brown       /* ... */
8030a96aa3bSJed Brown                                                                   /* don't use Morton order */
8049566063dSJacob Faibussowitsch       PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE));
8050a96aa3bSJed Brown #endif
8060a96aa3bSJed Brown     {
8070a96aa3bSJed Brown       PetscInt numLabels, l;
8080a96aa3bSJed Brown 
8099566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(base,&numLabels));
8100a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
8110a96aa3bSJed Brown         PetscBool  isDepth, isGhost, isVTK, isDim, isCellType;
8120a96aa3bSJed Brown         DMLabel    label, labelNew;
8130a96aa3bSJed Brown         PetscInt   defVal;
8140a96aa3bSJed Brown         const char *name;
8150a96aa3bSJed Brown 
8169566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(base, l, &name));
8179566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(base, l, &label));
8189566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"depth",&isDepth));
8190a96aa3bSJed Brown         if (isDepth) continue;
8209566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"dim",&isDim));
8210a96aa3bSJed Brown         if (isDim) continue;
8229566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"celltype",&isCellType));
8230a96aa3bSJed Brown         if (isCellType) continue;
8249566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"ghost",&isGhost));
8250a96aa3bSJed Brown         if (isGhost) continue;
8269566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"vtk",&isVTK));
8270a96aa3bSJed Brown         if (isVTK) continue;
8289566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,name));
8299566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm,name,&labelNew));
8309566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label,&defVal));
8319566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew,defVal));
8320a96aa3bSJed Brown       }
8330a96aa3bSJed Brown       /* map dm points (internal plex) to base
8340a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
8350a96aa3bSJed Brown          and propagating back to the coarsest
8360a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
8370a96aa3bSJed Brown          during DMForestTransferVecFromBase */
8389566063dSJacob Faibussowitsch       PetscCall(DMForestGetMinimumRefinement(dm,&l));
8390a96aa3bSJed Brown       if (!l) {
8409566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,"_forest_base_subpoint_map"));
8410a96aa3bSJed Brown       }
8420a96aa3bSJed Brown     }
8430a96aa3bSJed Brown   } else { /* construct from topology name */
8440a96aa3bSJed Brown     DMFTopology_pforest *topo;
8450a96aa3bSJed Brown 
8469566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreate_pforest(dm,topoName,&topo));
8470a96aa3bSJed Brown     pforest->topo = topo;
8480a96aa3bSJed Brown     /* TODO: construct base? */
8490a96aa3bSJed Brown   }
8500a96aa3bSJed Brown 
8510a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
8520a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
8530a96aa3bSJed Brown     DMLabel           adaptLabel;
8540a96aa3bSJed Brown     PetscInt          defaultValue;
8550a96aa3bSJed Brown     PetscInt          numValues, numValuesGlobal, cLocalStart, count;
8560a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
8570a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
8580a96aa3bSJed Brown     PetscBool         computeAdaptSF;
8590a96aa3bSJed Brown     p4est_topidx_t    flt, llt, t;
8600a96aa3bSJed Brown 
8610a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
8620a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
8630a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
8649566063dSJacob Faibussowitsch     PetscCall(DMForestGetComputeAdaptivitySF(dm,&computeAdaptSF));
8650a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_copy,(apforest->forest, 0)); /* 0 indicates no data copying */
8669566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm,&adaptLabel));
8670a96aa3bSJed Brown     if (adaptLabel) {
8680a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
8699566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(adaptLabel,&numValues));
8709566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&numValues,&numValuesGlobal,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)adaptFrom)));
8719566063dSJacob Faibussowitsch       PetscCall(DMLabelGetDefaultValue(adaptLabel,&defaultValue));
8720a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
8739566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
8749566063dSJacob Faibussowitsch         PetscCall(DMPforestGetRefinementLevel(dm,&ctx.currLevel));
8750a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8760a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_currlevel,NULL));
8770a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8780a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8790a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
8800a96aa3bSJed Brown         if (computeAdaptSF) {
8819566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL));
8820a96aa3bSJed Brown         }
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;
8860a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_uniform,NULL));
8870a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8880a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8890a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
8900a96aa3bSJed Brown         if (computeAdaptSF) {
8919566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL));
8920a96aa3bSJed Brown         }
8930a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
8949566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&ctx.maxLevel));
8950a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8960a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_uniform,NULL));
8970a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8980a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8990a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
9000a96aa3bSJed Brown         if (computeAdaptSF) {
9019566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,NULL));
9020a96aa3bSJed Brown         }
9030a96aa3bSJed Brown       } else if (numValuesGlobal) {
9040a96aa3bSJed Brown         p4est_t                    *p4est = pforest->forest;
9050a96aa3bSJed Brown         PetscInt                   *cellFlags;
9060a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
9070a96aa3bSJed Brown         PetscSF                    cellSF;
9080a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
9090a96aa3bSJed Brown         PetscBool                  adaptAny;
9100a96aa3bSJed Brown 
9119566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&ctx.maxLevel));
9129566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
9139566063dSJacob Faibussowitsch         PetscCall(DMForestGetAdaptivityStrategy(dm,&strategy));
9149566063dSJacob Faibussowitsch         PetscCall(PetscStrncmp(strategy,"any",3,&adaptAny));
9159566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellChart(adaptFrom,&cStart,&cEnd));
9169566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellSF(adaptFrom,&cellSF));
9179566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cEnd-cStart,&cellFlags));
9189566063dSJacob Faibussowitsch         for (c = cStart; c < cEnd; c++) PetscCall(DMLabelGetValue(adaptLabel,c,&cellFlags[c-cStart]));
9190a96aa3bSJed Brown         if (cellSF) {
9200a96aa3bSJed Brown           if (adaptAny) {
9219566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX));
9229566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX));
9230a96aa3bSJed Brown           } else {
9249566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN));
9259566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN));
9260a96aa3bSJed Brown           }
9270a96aa3bSJed Brown         }
9280a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
9290a96aa3bSJed Brown           p4est_tree_t       *tree    = &(((p4est_tree_t*) p4est->trees->array)[t]);
9300a96aa3bSJed Brown           PetscInt           numQuads = (PetscInt) tree->quadrants.elem_count, i;
9310a96aa3bSJed Brown           p4est_quadrant_t   *quads   = (p4est_quadrant_t *) tree->quadrants.array;
9320a96aa3bSJed Brown 
9330a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9340a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
9350a96aa3bSJed Brown             q->p.user_int = cellFlags[count++];
9360a96aa3bSJed Brown           }
9370a96aa3bSJed Brown         }
9389566063dSJacob Faibussowitsch         PetscCall(PetscFree(cellFlags));
9390a96aa3bSJed Brown 
9400a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
941*1baa6e33SBarry Smith         if (adaptAny) PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_any,pforest_init_determine));
942*1baa6e33SBarry Smith         else PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_all,pforest_init_determine));
9430a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_flag,NULL));
9440a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
9450a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
9460a96aa3bSJed Brown         if (computeAdaptSF) {
9479566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,&coarseToPreFine));
9480a96aa3bSJed Brown         }
9490a96aa3bSJed Brown       }
9500a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
9510a96aa3bSJed Brown         p4est_tree_t       *atree    = &(((p4est_tree_t*) apforest->forest->trees->array)[t]);
9520a96aa3bSJed Brown         p4est_tree_t       *tree     = &(((p4est_tree_t*) pforest->forest->trees->array)[t]);
9530a96aa3bSJed Brown         PetscInt           anumQuads = (PetscInt) atree->quadrants.elem_count, i;
9540a96aa3bSJed Brown         PetscInt           numQuads  = (PetscInt) tree->quadrants.elem_count;
9550a96aa3bSJed Brown         p4est_quadrant_t   *aquads   = (p4est_quadrant_t *) atree->quadrants.array;
9560a96aa3bSJed Brown         p4est_quadrant_t   *quads    = (p4est_quadrant_t *) tree->quadrants.array;
9570a96aa3bSJed Brown 
9580a96aa3bSJed Brown         if (anumQuads != numQuads) {
9590a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
9600a96aa3bSJed Brown         } else {
9610a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9620a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
9630a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
9640a96aa3bSJed Brown 
9650a96aa3bSJed Brown             if (aq->level != q->level) {
9660a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
9670a96aa3bSJed Brown               break;
9680a96aa3bSJed Brown             }
9690a96aa3bSJed Brown           }
9700a96aa3bSJed Brown         }
9710a96aa3bSJed Brown         if (ctx.anyChange) {
9720a96aa3bSJed Brown           break;
9730a96aa3bSJed Brown         }
9740a96aa3bSJed Brown       }
9750a96aa3bSJed Brown     }
9760a96aa3bSJed Brown     {
9770a96aa3bSJed Brown       PetscInt numLabels, l;
9780a96aa3bSJed Brown 
9799566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(adaptFrom,&numLabels));
9800a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
9810a96aa3bSJed Brown         PetscBool  isDepth, isCellType, isGhost, isVTK;
9820a96aa3bSJed Brown         DMLabel    label, labelNew;
9830a96aa3bSJed Brown         PetscInt   defVal;
9840a96aa3bSJed Brown         const char *name;
9850a96aa3bSJed Brown 
9869566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(adaptFrom, l, &name));
9879566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(adaptFrom, l, &label));
9889566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"depth",&isDepth));
9890a96aa3bSJed Brown         if (isDepth) continue;
9909566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"celltype",&isCellType));
9910a96aa3bSJed Brown         if (isCellType) continue;
9929566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"ghost",&isGhost));
9930a96aa3bSJed Brown         if (isGhost) continue;
9949566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"vtk",&isVTK));
9950a96aa3bSJed Brown         if (isVTK) continue;
9969566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,name));
9979566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm,name,&labelNew));
9989566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label,&defVal));
9999566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew,defVal));
10000a96aa3bSJed Brown       }
10010a96aa3bSJed Brown     }
10020a96aa3bSJed Brown   } else { /* initial */
10030a96aa3bSJed Brown     PetscInt initLevel, minLevel;
10040a96aa3bSJed Brown 
10059566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm,&initLevel));
10069566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
10070a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_new_ext,(PetscObjectComm((PetscObject)dm),pforest->topo->conn,
10080a96aa3bSJed Brown                                                              0,           /* minimum number of quadrants per processor */
10090a96aa3bSJed Brown                                                              initLevel,   /* level of refinement */
10100a96aa3bSJed Brown                                                              1,           /* uniform refinement */
10110a96aa3bSJed Brown                                                              0,           /* we don't allocate any per quadrant data */
10120a96aa3bSJed Brown                                                              NULL,        /* there is no special quadrant initialization */
10130a96aa3bSJed Brown                                                              (void*)dm)); /* this dm is the user context */
10140a96aa3bSJed Brown 
10150a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10160a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
10170a96aa3bSJed Brown       PetscBool  flgPattern, flgFractal;
10180a96aa3bSJed Brown       PetscInt   corner = 0;
10190a96aa3bSJed Brown       PetscInt   corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
10200a96aa3bSJed Brown       PetscReal  likelihood = 1./ P4EST_DIM;
10210a96aa3bSJed Brown       PetscInt   pattern;
10220a96aa3bSJed Brown       const char *prefix;
10230a96aa3bSJed Brown 
10249566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
10259566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEList(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_pattern",DMRefinePatternName,PATTERN_COUNT,&pattern,&flgPattern));
10269566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_corner",&corner,NULL));
10279566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_fractal_corners",corners,&ncorner,&flgFractal));
10289566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_hash_likelihood",&likelihood,NULL));
10290a96aa3bSJed Brown 
10300a96aa3bSJed Brown       if (flgPattern) {
10310a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
10320a96aa3bSJed Brown         PetscInt           maxLevel;
10330a96aa3bSJed Brown 
10349566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&maxLevel));
10359566063dSJacob Faibussowitsch         PetscCall(PetscNewLog(dm,&ctx));
10360a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel,P4EST_QMAXLEVEL);
10370a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10380a96aa3bSJed Brown         switch (pattern) {
10390a96aa3bSJed Brown         case PATTERN_HASH:
10400a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
10410a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
10420a96aa3bSJed Brown           break;
10430a96aa3bSJed Brown         case PATTERN_CORNER:
10440a96aa3bSJed Brown           ctx->corner    = corner;
10450a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
10460a96aa3bSJed Brown           break;
10470a96aa3bSJed Brown         case PATTERN_CENTER:
10480a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Center;
10490a96aa3bSJed Brown           break;
10500a96aa3bSJed Brown         case PATTERN_FRACTAL:
10510a96aa3bSJed Brown           if (flgFractal) {
10520a96aa3bSJed Brown             PetscInt i;
10530a96aa3bSJed Brown 
10540a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
10550a96aa3bSJed Brown           } else {
10560a96aa3bSJed Brown #if !defined(P4_TO_P8)
10570a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
10580a96aa3bSJed Brown #else
10590a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
10600a96aa3bSJed Brown #endif
10610a96aa3bSJed Brown           }
10620a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
10630a96aa3bSJed Brown           break;
10640a96aa3bSJed Brown         default:
10650a96aa3bSJed Brown           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Not a valid refinement pattern");
10660a96aa3bSJed Brown         }
10670a96aa3bSJed Brown 
10680a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) ctx;
10690a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,1,ctx->refine_fn,NULL));
10700a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
10719566063dSJacob Faibussowitsch         PetscCall(PetscFree(ctx));
10720a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
10730a96aa3bSJed Brown       }
10740a96aa3bSJed Brown     }
10750a96aa3bSJed Brown   }
10760a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
10770a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
10780a96aa3bSJed Brown 
10799566063dSJacob Faibussowitsch     PetscCall(DMPforestGetRefinementLevel(dm,&currLevel));
10809566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm,&initLevel));
10819566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
10820a96aa3bSJed Brown     if (currLevel > minLevel) {
10830a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
10840a96aa3bSJed Brown       DMLabel           coarsen;
10850a96aa3bSJed Brown       DM                coarseDM;
10860a96aa3bSJed Brown 
10879566063dSJacob Faibussowitsch       PetscCall(DMForestTemplate(dm,MPI_COMM_NULL,&coarseDM));
10889566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityPurpose(coarseDM,DM_ADAPT_COARSEN));
10899566063dSJacob Faibussowitsch       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen",&coarsen));
10909566063dSJacob Faibussowitsch       PetscCall(DMLabelSetDefaultValue(coarsen,DM_ADAPT_COARSEN));
10919566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityLabel(coarseDM,coarsen));
10929566063dSJacob Faibussowitsch       PetscCall(DMLabelDestroy(&coarsen));
10939566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm,coarseDM));
10949566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)coarseDM));
10950a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
10969566063dSJacob Faibussowitsch       PetscCall(DMForestSetInitialRefinement(coarseDM,initLevel));
10979566063dSJacob Faibussowitsch       PetscCall(DMForestSetMinimumRefinement(coarseDM,minLevel));
10980a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest*) ((DM_Forest*) coarseDM->data)->data;
10990a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
11000a96aa3bSJed Brown     }
11010a96aa3bSJed Brown   }
11020a96aa3bSJed Brown 
11030a96aa3bSJed Brown   { /* repartitioning and overlap */
11040a96aa3bSJed Brown     PetscMPIInt size, rank;
11050a96aa3bSJed Brown 
11069566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size));
11079566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
11080a96aa3bSJed Brown     if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
11090a96aa3bSJed Brown       PetscBool      copyForest   = PETSC_FALSE;
11100a96aa3bSJed Brown       p4est_t        *forest_copy = NULL;
11110a96aa3bSJed Brown       p4est_gloidx_t shipped      = 0;
11120a96aa3bSJed Brown 
11130a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
11140a96aa3bSJed Brown       if (copyForest) PetscStackCallP4estReturn(forest_copy,p4est_copy,(pforest->forest,0));
11150a96aa3bSJed Brown 
11160a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
11170a96aa3bSJed Brown         PetscStackCallP4estReturn(shipped,p4est_partition_ext,(pforest->forest,(int)pforest->partition_for_coarsening,NULL));
11180a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Non-uniform partition cases not implemented yet");
11190a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
11200a96aa3bSJed Brown       if (forest_copy) {
11210a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
11220a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
11230a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
11240a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
11250a96aa3bSJed Brown           PetscSFNode    *repartRoots;
11260a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
11270a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank+1];
11280a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
11290a96aa3bSJed Brown 
11300a96aa3bSJed Brown           numRoots  = (PetscInt) (forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
11310a96aa3bSJed Brown           numLeaves = (PetscInt) (postEnd - postStart);
11329566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeOverlappingRanks(size,rank,pforest->forest,forest_copy,&pStart,&pEnd));
11339566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1((PetscInt) pforest->forest->local_num_quadrants,&repartRoots));
11340a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
11350a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
11360a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p+1];
11370a96aa3bSJed Brown             PetscInt       q;
11380a96aa3bSJed Brown 
11390a96aa3bSJed Brown             if (preEnd == preStart) continue;
114008401ef6SPierre Jolivet             PetscCheck(preStart <= postStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Bad partition overlap computation");
11410a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
11420a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
11430a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
11440a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
11450a96aa3bSJed Brown             }
11460a96aa3bSJed Brown             partOffset = preEnd;
11470a96aa3bSJed Brown           }
11489566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&repartSF));
11499566063dSJacob Faibussowitsch           PetscCall(PetscSFSetGraph(repartSF,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,repartRoots,PETSC_OWN_POINTER));
11509566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(repartSF));
11510a96aa3bSJed Brown           if (preCoarseToFine) {
11520a96aa3bSJed Brown             PetscSF        repartSFembed, preCoarseToFineNew;
11530a96aa3bSJed Brown             PetscInt       nleaves;
11540a96aa3bSJed Brown             const PetscInt *leaves;
11550a96aa3bSJed Brown 
11569566063dSJacob Faibussowitsch             PetscCall(PetscSFSetUp(preCoarseToFine));
11579566063dSJacob Faibussowitsch             PetscCall(PetscSFGetGraph(preCoarseToFine,NULL,&nleaves,&leaves,NULL));
11580a96aa3bSJed Brown             if (leaves) {
11599566063dSJacob Faibussowitsch               PetscCall(PetscSFCreateEmbeddedRootSF(repartSF,nleaves,leaves,&repartSFembed));
11600a96aa3bSJed Brown             } else {
11610a96aa3bSJed Brown               repartSFembed = repartSF;
11629566063dSJacob Faibussowitsch               PetscCall(PetscObjectReference((PetscObject)repartSFembed));
11630a96aa3bSJed Brown             }
11649566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(preCoarseToFine,repartSFembed,&preCoarseToFineNew));
11659566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&preCoarseToFine));
11669566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFembed));
11670a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
11680a96aa3bSJed Brown           }
11690a96aa3bSJed Brown           if (coarseToPreFine) {
11700a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
11710a96aa3bSJed Brown 
11729566063dSJacob Faibussowitsch             PetscCall(PetscSFCreateInverseSF(repartSF,&repartSFinv));
11739566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(repartSFinv,coarseToPreFine,&coarseToPreFineNew));
11749566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&coarseToPreFine));
11759566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFinv));
11760a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
11770a96aa3bSJed Brown           }
11789566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&repartSF));
11790a96aa3bSJed Brown         }
11800a96aa3bSJed Brown         PetscStackCallP4est(p4est_destroy,(forest_copy));
11810a96aa3bSJed Brown       }
11820a96aa3bSJed Brown     }
11830a96aa3bSJed Brown     if (size > 1) {
11840a96aa3bSJed Brown       PetscInt overlap;
11850a96aa3bSJed Brown 
11869566063dSJacob Faibussowitsch       PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
11870a96aa3bSJed Brown 
11880a96aa3bSJed Brown       if (adaptFrom) {
11890a96aa3bSJed Brown         PetscInt aoverlap;
11900a96aa3bSJed Brown 
11919566063dSJacob Faibussowitsch         PetscCall(DMForestGetPartitionOverlap(adaptFrom,&aoverlap));
11920a96aa3bSJed Brown         if (aoverlap != overlap) {
11930a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
11940a96aa3bSJed Brown         }
11950a96aa3bSJed Brown       }
11960a96aa3bSJed Brown 
11970a96aa3bSJed Brown       if (overlap > 0) {
11980a96aa3bSJed Brown         PetscInt i, cLocalStart;
11990a96aa3bSJed Brown         PetscInt cEnd;
12000a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
12010a96aa3bSJed Brown 
12020a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->ghost,p4est_ghost_new,(pforest->forest,P4EST_CONNECT_FULL));
12030a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->lnodes,p4est_lnodes_new,(pforest->forest,pforest->ghost,-P4EST_DIM));
12040a96aa3bSJed Brown         PetscStackCallP4est(p4est_ghost_support_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
12050a96aa3bSJed Brown         for (i = 1; i < overlap; i++) PetscStackCallP4est(p4est_ghost_expand_by_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
12060a96aa3bSJed Brown 
12070a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
12080a96aa3bSJed Brown         cEnd        = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
12090a96aa3bSJed Brown 
12100a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
12110a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
12129566063dSJacob Faibussowitsch           if (adaptFrom) PetscCall(DMForestGetCellSF(adaptFrom,&preCellSF));
12130a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
12149566063dSJacob Faibussowitsch           PetscCall(DMForestGetCellSF(dm,&cellSF));
12150a96aa3bSJed Brown         }
12160a96aa3bSJed Brown         if (preCoarseToFine) {
12170a96aa3bSJed Brown           PetscSF           preCoarseToFineNew;
12180a96aa3bSJed Brown           PetscInt          nleaves, nroots, *leavesNew, i, nleavesNew;
12190a96aa3bSJed Brown           const PetscInt    *leaves;
12200a96aa3bSJed Brown           const PetscSFNode *remotes;
12210a96aa3bSJed Brown           PetscSFNode       *remotesAll;
12220a96aa3bSJed Brown 
12239566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(preCoarseToFine));
12249566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCoarseToFine,&nroots,&nleaves,&leaves,&remotes));
12259566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(cEnd,&remotesAll));
12260a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
12270a96aa3bSJed Brown             remotesAll[i].rank  = -1;
12280a96aa3bSJed Brown             remotesAll[i].index = -1;
12290a96aa3bSJed Brown           }
12300a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
12319566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(cellSF));
12329566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE));
12339566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE));
12340a96aa3bSJed Brown           nleavesNew = 0;
12350a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12360a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
12370a96aa3bSJed Brown           }
12389566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesNew,&leavesNew));
12390a96aa3bSJed Brown           nleavesNew = 0;
12400a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12410a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
12420a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
12430a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
12440a96aa3bSJed Brown               nleavesNew++;
12450a96aa3bSJed Brown             }
12460a96aa3bSJed Brown           }
12479566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&preCoarseToFineNew));
12480a96aa3bSJed Brown           if (nleavesNew < cEnd) {
12499566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,leavesNew,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES));
12500a96aa3bSJed Brown           } else { /* all cells are leaves */
12519566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
12529566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,NULL,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES));
12530a96aa3bSJed Brown           }
12549566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesAll));
12559566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&preCoarseToFine));
12560a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12570a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12580a96aa3bSJed Brown         }
12590a96aa3bSJed Brown         if (coarseToPreFine) {
12600a96aa3bSJed Brown           PetscSF           coarseToPreFineNew;
12610a96aa3bSJed Brown           PetscInt          nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
12620a96aa3bSJed Brown           const PetscInt    *leaves;
12630a96aa3bSJed Brown           const PetscSFNode *remotes;
12640a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
12650a96aa3bSJed Brown 
12669566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(coarseToPreFine));
12679566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseToPreFine,&nroots,&nleaves,&leaves,&remotes));
12689566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCellSF,NULL,&nleavesCellSF,NULL,NULL));
12699566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nroots,&remotesNewRoot));
12709566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleaves,&remotesNew));
12710a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
12720a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
12730a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
12740a96aa3bSJed Brown           }
12759566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE));
12769566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE));
12779566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNewRoot));
12789566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesCellSF,&remotesExpanded));
12790a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12800a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
12810a96aa3bSJed Brown             remotesExpanded[i].index = -1;
12820a96aa3bSJed Brown           }
12830a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
12849566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNew));
12859566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE));
12869566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE));
12870a96aa3bSJed Brown 
12880a96aa3bSJed Brown           nleavesExpanded = 0;
12890a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12900a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
12910a96aa3bSJed Brown           }
12929566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesExpanded,&leavesNew));
12930a96aa3bSJed Brown           nleavesExpanded = 0;
12940a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12950a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
12960a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
12970a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
12980a96aa3bSJed Brown               nleavesExpanded++;
12990a96aa3bSJed Brown             }
13000a96aa3bSJed Brown           }
13019566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&coarseToPreFineNew));
13020a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
13039566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,leavesNew,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES));
13040a96aa3bSJed Brown           } else {
13059566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
13069566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,NULL,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES));
13070a96aa3bSJed Brown           }
13089566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesExpanded));
13099566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseToPreFine));
13100a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
13110a96aa3bSJed Brown         }
13120a96aa3bSJed Brown       }
13130a96aa3bSJed Brown     }
13140a96aa3bSJed Brown   }
13150a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
13160a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
13170a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
13189566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&ctx.anyChange,&(pforest->adaptivitySuccess),1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm)));
13199566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,NULL));
13200a96aa3bSJed Brown   PetscFunctionReturn(0);
13210a96aa3bSJed Brown }
13220a96aa3bSJed Brown 
13230a96aa3bSJed Brown #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
13240a96aa3bSJed Brown static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success)
13250a96aa3bSJed Brown {
13260a96aa3bSJed Brown   DM_Forest         *forest;
13270a96aa3bSJed Brown   DM_Forest_pforest *pforest;
13280a96aa3bSJed Brown 
13290a96aa3bSJed Brown   PetscFunctionBegin;
13300a96aa3bSJed Brown   forest   = (DM_Forest *) dm->data;
13310a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *) forest->data;
13320a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
13330a96aa3bSJed Brown   PetscFunctionReturn(0);
13340a96aa3bSJed Brown }
13350a96aa3bSJed Brown 
13360a96aa3bSJed Brown #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
13370a96aa3bSJed Brown static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer)
13380a96aa3bSJed Brown {
13390a96aa3bSJed Brown   DM             dm = (DM) odm;
13400a96aa3bSJed Brown 
13410a96aa3bSJed Brown   PetscFunctionBegin;
13420a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13430a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13449566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13450a96aa3bSJed Brown   switch (viewer->format) {
13460a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
13470a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO:
13480a96aa3bSJed Brown   {
13490a96aa3bSJed Brown     PetscInt   dim;
13500a96aa3bSJed Brown     const char *name;
13510a96aa3bSJed Brown 
13529566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
13539566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
135463a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "Forest %s in %" PetscInt_FMT " dimensions:\n", name, dim));
135563a3b9bcSJacob Faibussowitsch     else      PetscCall(PetscViewerASCIIPrintf(viewer, "Forest in %" PetscInt_FMT " dimensions:\n", dim));
13560a96aa3bSJed Brown   }
13570a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
13580a96aa3bSJed Brown   case PETSC_VIEWER_LOAD_BALANCE:
13590a96aa3bSJed Brown   {
13600a96aa3bSJed Brown     DM plex;
13610a96aa3bSJed Brown 
13629566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dm, &plex));
13639566063dSJacob Faibussowitsch     PetscCall(DMView(plex, viewer));
13640a96aa3bSJed Brown   }
13650a96aa3bSJed Brown   break;
136698921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13670a96aa3bSJed Brown   }
13680a96aa3bSJed Brown   PetscFunctionReturn(0);
13690a96aa3bSJed Brown }
13700a96aa3bSJed Brown 
13710a96aa3bSJed Brown #define DMView_VTK_pforest _append_pforest(DMView_VTK)
13720a96aa3bSJed Brown static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer)
13730a96aa3bSJed Brown {
13740a96aa3bSJed Brown   DM                dm       = (DM) odm;
13750a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
13760a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
13770a96aa3bSJed Brown   PetscBool         isvtk;
13780a96aa3bSJed Brown   PetscReal         vtkScale = 1. - PETSC_MACHINE_EPSILON;
13790a96aa3bSJed Brown   PetscViewer_VTK   *vtk     = (PetscViewer_VTK*)viewer->data;
13800a96aa3bSJed Brown   const char        *name;
13810a96aa3bSJed Brown   char              *filenameStrip = NULL;
13820a96aa3bSJed Brown   PetscBool         hasExt;
13830a96aa3bSJed Brown   size_t            len;
13840a96aa3bSJed Brown   p4est_geometry_t  *geom;
13850a96aa3bSJed Brown 
13860a96aa3bSJed Brown   PetscFunctionBegin;
13870a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13880a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13899566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13900a96aa3bSJed Brown   geom = pforest->topo->geom;
13919566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk));
139228b400f6SJacob Faibussowitsch   PetscCheck(isvtk,PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
13930a96aa3bSJed Brown   switch (viewer->format) {
13940a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
139528b400f6SJacob Faibussowitsch     PetscCheck(pforest->forest,PetscObjectComm(odm),PETSC_ERR_ARG_WRONG,"DM has not been setup with a valid forest");
13960a96aa3bSJed Brown     name = vtk->filename;
13979566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(name,&len));
13989566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(name+len-4,".vtu",&hasExt));
13990a96aa3bSJed Brown     if (hasExt) {
14009566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(name,&filenameStrip));
14010a96aa3bSJed Brown       filenameStrip[len-4]='\0';
14020a96aa3bSJed Brown       name                = filenameStrip;
14030a96aa3bSJed Brown     }
14040a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4estReturn(geom,p4est_geometry_new_connectivity,(pforest->topo->conn));
14050a96aa3bSJed Brown     {
14060a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
14070a96aa3bSJed Brown       int                 footerr;
14080a96aa3bSJed Brown 
14090a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_context_new,(pforest->forest,name));
14100a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_geom,(pvtk,geom));
14110a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_scale,(pvtk,(double)vtkScale));
14120a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_header,(pvtk));
141328b400f6SJacob Faibussowitsch       PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_header() failed");
14140a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_cell_dataf,(pvtk,
14150a96aa3bSJed Brown                                                                  1, /* write tree */
14160a96aa3bSJed Brown                                                                  1, /* write level */
14170a96aa3bSJed Brown                                                                  1, /* write rank */
14180a96aa3bSJed Brown                                                                  0, /* do not wrap rank */
14190a96aa3bSJed Brown                                                                  0, /* no scalar fields */
14200a96aa3bSJed Brown                                                                  0, /* no vector fields */
14210a96aa3bSJed Brown                                                                  pvtk));
142228b400f6SJacob Faibussowitsch       PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_cell_dataf() failed");
14230a96aa3bSJed Brown       PetscStackCallP4estReturn(footerr,p4est_vtk_write_footer,(pvtk));
142428b400f6SJacob Faibussowitsch       PetscCheck(!footerr,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_footer() failed");
14250a96aa3bSJed Brown     }
14260a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4est(p4est_geometry_destroy,(geom));
14279566063dSJacob Faibussowitsch     PetscCall(PetscFree(filenameStrip));
14280a96aa3bSJed Brown     break;
142998921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
14300a96aa3bSJed Brown   }
14310a96aa3bSJed Brown   PetscFunctionReturn(0);
14320a96aa3bSJed Brown }
14330a96aa3bSJed Brown 
14340a96aa3bSJed Brown #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
14350a96aa3bSJed Brown static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer)
14360a96aa3bSJed Brown {
14370a96aa3bSJed Brown   DM             plex;
14380a96aa3bSJed Brown 
14390a96aa3bSJed Brown   PetscFunctionBegin;
14409566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14419566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14429566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14430a96aa3bSJed Brown   PetscFunctionReturn(0);
14440a96aa3bSJed Brown }
14450a96aa3bSJed Brown 
14460a96aa3bSJed Brown #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
14470a96aa3bSJed Brown static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer)
14480a96aa3bSJed Brown {
14490a96aa3bSJed Brown   DM             plex;
14500a96aa3bSJed Brown 
14510a96aa3bSJed Brown   PetscFunctionBegin;
14529566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14539566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14549566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14550a96aa3bSJed Brown   PetscFunctionReturn(0);
14560a96aa3bSJed Brown }
14570a96aa3bSJed Brown 
14580a96aa3bSJed Brown #define DMView_pforest _append_pforest(DMView)
14590a96aa3bSJed Brown static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer)
14600a96aa3bSJed Brown {
14610a96aa3bSJed Brown   PetscBool      isascii, isvtk, ishdf5, isglvis;
14620a96aa3bSJed Brown 
14630a96aa3bSJed Brown   PetscFunctionBegin;
14640a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14650a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
14669566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii));
14679566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk));
14689566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5));
14699566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis));
14700a96aa3bSJed Brown   if (isascii) {
14719566063dSJacob Faibussowitsch     PetscCall(DMView_ASCII_pforest((PetscObject) dm,viewer));
14720a96aa3bSJed Brown   } else if (isvtk) {
14739566063dSJacob Faibussowitsch     PetscCall(DMView_VTK_pforest((PetscObject) dm,viewer));
14740a96aa3bSJed Brown   } else if (ishdf5) {
14759566063dSJacob Faibussowitsch     PetscCall(DMView_HDF5_pforest(dm, viewer));
14760a96aa3bSJed Brown   } else if (isglvis) {
14779566063dSJacob Faibussowitsch     PetscCall(DMView_GLVis_pforest(dm, viewer));
14780a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject) dm),PETSC_ERR_SUP,"Viewer not supported (not VTK, HDF5, or GLVis)");
14790a96aa3bSJed Brown   PetscFunctionReturn(0);
14800a96aa3bSJed Brown }
14810a96aa3bSJed Brown 
14820a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq)
14830a96aa3bSJed Brown {
14840a96aa3bSJed Brown   PetscInt       *ttf, f, t, g, count;
14850a96aa3bSJed Brown   PetscInt       numFacets;
14860a96aa3bSJed Brown 
14870a96aa3bSJed Brown   PetscFunctionBegin;
14880a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
14899566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFacets,&ttf));
14900a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
14910a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
14920a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
14930a96aa3bSJed Brown       if (ttf[g] == -1) {
14940a96aa3bSJed Brown         PetscInt ng;
14950a96aa3bSJed Brown 
14960a96aa3bSJed Brown         ttf[g]  = count++;
14970a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
14980a96aa3bSJed Brown         ttf[ng] = ttf[g];
14990a96aa3bSJed Brown       }
15000a96aa3bSJed Brown     }
15010a96aa3bSJed Brown   }
15020a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
15030a96aa3bSJed Brown   PetscFunctionReturn(0);
15040a96aa3bSJed Brown }
15050a96aa3bSJed Brown 
15060a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq)
15070a96aa3bSJed Brown {
15080a96aa3bSJed Brown   p4est_topidx_t       numTrees, numVerts, numCorns, numCtt;
15090a96aa3bSJed Brown   PetscSection         ctt;
15100a96aa3bSJed Brown #if defined(P4_TO_P8)
15110a96aa3bSJed Brown   p4est_topidx_t       numEdges, numEtt;
15120a96aa3bSJed Brown   PetscSection         ett;
15130a96aa3bSJed Brown   PetscInt             eStart, eEnd, e, ettSize;
15140a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES + P8EST_EDGES;
15150a96aa3bSJed Brown   PetscInt             edgeOff = 1 + P4EST_FACES;
15160a96aa3bSJed Brown #else
15170a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES;
15180a96aa3bSJed Brown #endif
15190a96aa3bSJed Brown   p4est_connectivity_t *conn;
15200a96aa3bSJed Brown   PetscInt             cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
15210a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
15220a96aa3bSJed Brown   PetscInt             *ttf;
15230a96aa3bSJed Brown 
15240a96aa3bSJed Brown   PetscFunctionBegin;
15250a96aa3bSJed Brown   /* 1: count objects, allocate */
15269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd));
15279566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cEnd-cStart,&numTrees));
15280a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
15299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd));
15309566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(vEnd-vStart,&numCorns));
15319566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&ctt));
15329566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ctt,vStart,vEnd));
15330a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
15340a96aa3bSJed Brown     PetscInt s;
15350a96aa3bSJed Brown 
15369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
15370a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15380a96aa3bSJed Brown       PetscInt p = star[2*s];
15390a96aa3bSJed Brown 
15400a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15410a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
15420a96aa3bSJed Brown          * only protects against periodicity problems */
15439566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
154463a3b9bcSJacob 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);
15450a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
15460a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
15470a96aa3bSJed Brown 
15481dca8a05SBarry Smith           PetscCheck(cellVert >= vStart && cellVert < vEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: vertices");
15490a96aa3bSJed Brown           if (cellVert == v) {
15509566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(ctt,v,1));
15510a96aa3bSJed Brown           }
15520a96aa3bSJed Brown         }
15539566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15540a96aa3bSJed Brown       }
15550a96aa3bSJed Brown     }
15569566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
15570a96aa3bSJed Brown   }
15589566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ctt));
15599566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ctt,&cttSize));
15609566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cttSize,&numCtt));
15610a96aa3bSJed Brown #if defined(P4_TO_P8)
15629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,P4EST_DIM-1,&eStart,&eEnd));
15639566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(eEnd-eStart,&numEdges));
15649566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&ett));
15659566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ett,eStart,eEnd));
15660a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
15670a96aa3bSJed Brown     PetscInt s;
15680a96aa3bSJed Brown 
15699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
15700a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15710a96aa3bSJed Brown       PetscInt p = star[2*s];
15720a96aa3bSJed Brown 
15730a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15740a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
15750a96aa3bSJed Brown          * only protects against periodicity problems */
15769566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
157708401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell with wrong closure size");
15780a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
15790a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
15800a96aa3bSJed Brown 
15811dca8a05SBarry Smith           PetscCheck(cellEdge >= eStart && cellEdge < eEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: edges");
15820a96aa3bSJed Brown           if (cellEdge == e) {
15839566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(ett,e,1));
15840a96aa3bSJed Brown           }
15850a96aa3bSJed Brown         }
15869566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15870a96aa3bSJed Brown       }
15880a96aa3bSJed Brown     }
15899566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
15900a96aa3bSJed Brown   }
15919566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ett));
15929566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ett,&ettSize));
15939566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(ettSize,&numEtt));
15940a96aa3bSJed Brown 
15950a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
15960a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p8est_connectivity_new,(numVerts,numTrees,numEdges,numEtt,numCorns,numCtt));
15970a96aa3bSJed Brown #else
15980a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p4est_connectivity_new,(numVerts,numTrees,numCorns,numCtt));
15990a96aa3bSJed Brown #endif
16000a96aa3bSJed Brown 
16010a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
16029566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,1,&fStart,&fEnd));
16039566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((cEnd-cStart) * P4EST_FACES,&ttf));
16040a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
16050a96aa3bSJed Brown     PetscInt       numSupp, s;
16060a96aa3bSJed Brown     PetscInt       myFace[2] = {-1, -1};
16070a96aa3bSJed Brown     PetscInt       myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
16080a96aa3bSJed Brown     const PetscInt *supp;
16090a96aa3bSJed Brown 
16109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numSupp));
16111dca8a05SBarry 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);
16129566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &supp));
16130a96aa3bSJed Brown 
16140a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16150a96aa3bSJed Brown       PetscInt p = supp[s];
16160a96aa3bSJed Brown 
16170a96aa3bSJed Brown       if (p >= cEnd) {
16180a96aa3bSJed Brown         numSupp--;
16190a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
16200a96aa3bSJed Brown         break;
16210a96aa3bSJed Brown       }
16220a96aa3bSJed Brown     }
16230a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16240a96aa3bSJed Brown       PetscInt       p = supp[s], i;
16250a96aa3bSJed Brown       PetscInt       numCone;
16260a96aa3bSJed Brown       DMPolytopeType ct;
16270a96aa3bSJed Brown       const PetscInt *cone;
16280a96aa3bSJed Brown       const PetscInt *ornt;
16290a96aa3bSJed Brown       PetscInt       orient = PETSC_MIN_INT;
16300a96aa3bSJed Brown 
16319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &numCone));
163263a3b9bcSJacob 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);
16339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
16349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[0], &ct));
16359566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
16360a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
16370a96aa3bSJed Brown         if (cone[i] == f) {
16380a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
16390a96aa3bSJed Brown           break;
16400a96aa3bSJed Brown         }
16410a96aa3bSJed Brown       }
164263a3b9bcSJacob Faibussowitsch       PetscCheck(i < P4EST_FACES,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %" PetscInt_FMT " faced %" PetscInt_FMT " mismatch",p,f);
16430a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
16440a96aa3bSJed Brown         DMPolytopeType ct;
16459566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
164663a3b9bcSJacob 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);
16470a96aa3bSJed Brown       }
16480a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
16490a96aa3bSJed Brown       if (numSupp == 1) {
16500a96aa3bSJed Brown         /* boundary faces indicated by self reference */
16510a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
16520a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t) PetscFaceToP4estFace[i];
16530a96aa3bSJed Brown       } else {
16540a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16550a96aa3bSJed Brown 
16560a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
16570a96aa3bSJed Brown         myFace[s] = PetscFaceToP4estFace[i];
16580a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
16590a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
16600a96aa3bSJed Brown         myOrnt[s] = DihedralCompose(N,orient,DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
16610a96aa3bSJed Brown       }
16620a96aa3bSJed Brown     }
16630a96aa3bSJed Brown     if (numSupp == 2) {
16640a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
16650a96aa3bSJed Brown         PetscInt       p = supp[s];
16660a96aa3bSJed Brown         PetscInt       orntAtoB;
16670a96aa3bSJed Brown         PetscInt       p4estOrient;
16680a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16690a96aa3bSJed Brown 
16700a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
16710a96aa3bSJed Brown          * permutation of this cell-facet's cone */
16720a96aa3bSJed Brown         orntAtoB = DihedralCompose(N,DihedralInvert(N,myOrnt[1-s]),myOrnt[s]);
16730a96aa3bSJed Brown 
16740a96aa3bSJed Brown         /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
16750a96aa3bSJed Brown          * vertices around facet) */
16760a96aa3bSJed Brown #if !defined(P4_TO_P8)
16770a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
16780a96aa3bSJed Brown #else
16790a96aa3bSJed Brown         {
16800a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
16810a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
16820a96aa3bSJed Brown 
16830a96aa3bSJed Brown                                                                                            /* swap bits */
16840a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
16850a96aa3bSJed Brown         }
16860a96aa3bSJed Brown #endif
16870a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
16880a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
16890a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t) myFace[1 - s] + p4estOrient * P4EST_FACES;
16900a96aa3bSJed Brown       }
16910a96aa3bSJed Brown     }
16920a96aa3bSJed Brown   }
16930a96aa3bSJed Brown 
16940a96aa3bSJed Brown #if defined(P4_TO_P8)
16950a96aa3bSJed Brown   /* 3: visit every edge */
16960a96aa3bSJed Brown   conn->ett_offset[0] = 0;
16970a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
16980a96aa3bSJed Brown     PetscInt off, s;
16990a96aa3bSJed Brown 
17009566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ett,e,&off));
17010a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t) off;
17029566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
17030a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17040a96aa3bSJed Brown       PetscInt p = star[2 * s];
17050a96aa3bSJed Brown 
17060a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17079566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
170808401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
17090a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
17100a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
17110a96aa3bSJed Brown           PetscInt cellOrnt = closure[2 * (c + edgeOff) + 1];
17120a96aa3bSJed Brown           DMPolytopeType ct;
17130a96aa3bSJed Brown 
17149566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cellEdge, &ct));
17150a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
17160a96aa3bSJed Brown           if (cellEdge == e) {
17170a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
17180a96aa3bSJed Brown             PetscInt totalOrient;
17190a96aa3bSJed Brown 
17200a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
17210a96aa3bSJed Brown             totalOrient = DihedralCompose(2,cellOrnt,DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
17220a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
17230a96aa3bSJed Brown             totalOrient             = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
17240a96aa3bSJed Brown             conn->edge_to_tree[off] = (p4est_locidx_t) (p - cStart);
17250a96aa3bSJed Brown             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standart (see
17260a96aa3bSJed Brown              * p8est_connectivity.h) */
17270a96aa3bSJed Brown             conn->edge_to_edge[off++] = (int8_t) p4estEdge + P8EST_EDGES * totalOrient;
17280a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
17290a96aa3bSJed Brown           }
17300a96aa3bSJed Brown         }
17319566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17320a96aa3bSJed Brown       }
17330a96aa3bSJed Brown     }
17349566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
17350a96aa3bSJed Brown   }
17369566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ett));
17370a96aa3bSJed Brown #endif
17380a96aa3bSJed Brown 
17390a96aa3bSJed Brown   /* 4: visit every vertex */
17400a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
17410a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
17420a96aa3bSJed Brown     PetscInt off, s;
17430a96aa3bSJed Brown 
17449566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ctt,v,&off));
17450a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t) off;
17469566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
17470a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17480a96aa3bSJed Brown       PetscInt p = star[2 * s];
17490a96aa3bSJed Brown 
17500a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17519566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
175208401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
17530a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
17540a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
17550a96aa3bSJed Brown 
17560a96aa3bSJed Brown           if (cellVert == v) {
17570a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
17580a96aa3bSJed Brown 
17590a96aa3bSJed Brown             conn->corner_to_tree[off]     = (p4est_locidx_t) (p - cStart);
17600a96aa3bSJed Brown             conn->corner_to_corner[off++] = (int8_t) p4estVert;
17610a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
17620a96aa3bSJed Brown           }
17630a96aa3bSJed Brown         }
17649566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17650a96aa3bSJed Brown       }
17660a96aa3bSJed Brown     }
17679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
17680a96aa3bSJed Brown   }
17699566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ctt));
17700a96aa3bSJed Brown 
17710a96aa3bSJed Brown   /* 5: Compute the coordinates */
17720a96aa3bSJed Brown   {
17730a96aa3bSJed Brown     PetscInt     coordDim;
17740a96aa3bSJed Brown     Vec          coordVec;
17750a96aa3bSJed Brown     PetscSection coordSec;
17760a96aa3bSJed Brown     PetscBool    localized;
17770a96aa3bSJed Brown 
17789566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
17799566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
17809566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocalizedLocal(dm, &localized));
17819566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &coordSec));
17820a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
17830a96aa3bSJed Brown       PetscInt    dof;
17840a96aa3bSJed Brown       PetscScalar *cellCoords = NULL;
17850a96aa3bSJed Brown 
17869566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSec, coordVec, c, &dof, &cellCoords));
17871dca8a05SBarry Smith       PetscCheck(localized || 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);
17880a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
17890a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
17900a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
17910a96aa3bSJed Brown 
17920a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
17930a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
17940a96aa3bSJed Brown         for (i = 0; i < 3; i++)   conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
17950a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
17960a96aa3bSJed Brown       }
17979566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSec, coordVec, c, &dof, &cellCoords));
17980a96aa3bSJed Brown     }
17990a96aa3bSJed Brown   }
18000a96aa3bSJed Brown 
18010a96aa3bSJed Brown #if defined(P4EST_ENABLE_DEBUG)
180208401ef6SPierre Jolivet   PetscCheck(p4est_connectivity_is_valid(conn),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Plex to p4est conversion failed");
18030a96aa3bSJed Brown #endif
18040a96aa3bSJed Brown 
18050a96aa3bSJed Brown   *connOut = conn;
18060a96aa3bSJed Brown 
18070a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
18080a96aa3bSJed Brown 
18090a96aa3bSJed Brown   PetscFunctionReturn(0);
18100a96aa3bSJed Brown }
18110a96aa3bSJed Brown 
18120a96aa3bSJed Brown static PetscErrorCode locidx_to_PetscInt(sc_array_t * array)
18130a96aa3bSJed Brown {
18140a96aa3bSJed Brown   sc_array_t *newarray;
18150a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18160a96aa3bSJed Brown 
18170a96aa3bSJed Brown   PetscFunctionBegin;
181808401ef6SPierre Jolivet   PetscCheck(array->elem_size == sizeof(p4est_locidx_t),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
18190a96aa3bSJed Brown 
18200a96aa3bSJed Brown   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(0);
18210a96aa3bSJed Brown 
18220a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscInt), array->elem_count);
18230a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18240a96aa3bSJed Brown     p4est_locidx_t il  = *((p4est_locidx_t*) sc_array_index (array, zz));
18250a96aa3bSJed Brown     PetscInt       *ip = (PetscInt*) sc_array_index (newarray, zz);
18260a96aa3bSJed Brown 
18270a96aa3bSJed Brown     *ip = (PetscInt) il;
18280a96aa3bSJed Brown   }
18290a96aa3bSJed Brown 
18300a96aa3bSJed Brown   sc_array_reset (array);
18310a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscInt), count);
18320a96aa3bSJed Brown   sc_array_copy (array, newarray);
18330a96aa3bSJed Brown   sc_array_destroy (newarray);
18340a96aa3bSJed Brown   PetscFunctionReturn(0);
18350a96aa3bSJed Brown }
18360a96aa3bSJed Brown 
18370a96aa3bSJed Brown static PetscErrorCode coords_double_to_PetscScalar(sc_array_t * array, PetscInt dim)
18380a96aa3bSJed Brown {
18390a96aa3bSJed Brown   sc_array_t *newarray;
18400a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18410a96aa3bSJed Brown 
18420a96aa3bSJed Brown   PetscFunctionBegin;
18431dca8a05SBarry Smith   PetscCheck(array->elem_size == 3 * sizeof(double),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong coordinate size");
18440a96aa3bSJed Brown #if !defined(PETSC_USE_COMPLEX)
18450a96aa3bSJed Brown   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(0);
18460a96aa3bSJed Brown #endif
18470a96aa3bSJed Brown 
18480a96aa3bSJed Brown   newarray = sc_array_new_size (dim * sizeof(PetscScalar), array->elem_count);
18490a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18500a96aa3bSJed Brown     int         i;
18510a96aa3bSJed Brown     double      *id = (double*) sc_array_index (array, zz);
18520a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar*) sc_array_index (newarray, zz);
18530a96aa3bSJed Brown 
18540a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
18550a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim,3); i++) ip[i] = (PetscScalar) id[i];
18560a96aa3bSJed Brown   }
18570a96aa3bSJed Brown 
18580a96aa3bSJed Brown   sc_array_reset (array);
18590a96aa3bSJed Brown   sc_array_init_size (array, dim * sizeof(PetscScalar), count);
18600a96aa3bSJed Brown   sc_array_copy (array, newarray);
18610a96aa3bSJed Brown   sc_array_destroy (newarray);
18620a96aa3bSJed Brown   PetscFunctionReturn(0);
18630a96aa3bSJed Brown }
18640a96aa3bSJed Brown 
18650a96aa3bSJed Brown static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t * array)
18660a96aa3bSJed Brown {
18670a96aa3bSJed Brown   sc_array_t *newarray;
18680a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18690a96aa3bSJed Brown 
18700a96aa3bSJed Brown   PetscFunctionBegin;
18711dca8a05SBarry Smith   PetscCheck(array->elem_size == 2 * sizeof(p4est_locidx_t),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
18720a96aa3bSJed Brown 
18730a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscSFNode), array->elem_count);
18740a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18750a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t*) sc_array_index (array, zz);
18760a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode*) sc_array_index (newarray, zz);
18770a96aa3bSJed Brown 
18780a96aa3bSJed Brown     ip->rank  = (PetscInt) il[0];
18790a96aa3bSJed Brown     ip->index = (PetscInt) il[1];
18800a96aa3bSJed Brown   }
18810a96aa3bSJed Brown 
18820a96aa3bSJed Brown   sc_array_reset (array);
18830a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscSFNode), count);
18840a96aa3bSJed Brown   sc_array_copy (array, newarray);
18850a96aa3bSJed Brown   sc_array_destroy (newarray);
18860a96aa3bSJed Brown   PetscFunctionReturn(0);
18870a96aa3bSJed Brown }
18880a96aa3bSJed Brown 
18890a96aa3bSJed Brown static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM * plex)
18900a96aa3bSJed Brown {
18910a96aa3bSJed Brown   PetscFunctionBegin;
18920a96aa3bSJed Brown   {
18930a96aa3bSJed Brown     sc_array_t     *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
18940a96aa3bSJed Brown     sc_array_t     *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
18950a96aa3bSJed Brown     sc_array_t     *cones             = sc_array_new(sizeof(p4est_locidx_t));
18960a96aa3bSJed Brown     sc_array_t     *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
18970a96aa3bSJed Brown     sc_array_t     *coords            = sc_array_new(3 * sizeof(double));
18980a96aa3bSJed Brown     sc_array_t     *children          = sc_array_new(sizeof(p4est_locidx_t));
18990a96aa3bSJed Brown     sc_array_t     *parents           = sc_array_new(sizeof(p4est_locidx_t));
19000a96aa3bSJed Brown     sc_array_t     *childids          = sc_array_new(sizeof(p4est_locidx_t));
19010a96aa3bSJed Brown     sc_array_t     *leaves            = sc_array_new(sizeof(p4est_locidx_t));
19020a96aa3bSJed Brown     sc_array_t     *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
19030a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
19040a96aa3bSJed Brown 
19050a96aa3bSJed Brown     PetscStackCallP4est(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));
19060a96aa3bSJed Brown 
19079566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
19089566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
19099566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
19109566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
19119566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, P4EST_DIM));
19120a96aa3bSJed Brown 
19139566063dSJacob Faibussowitsch     PetscCall(DMPlexCreate(PETSC_COMM_SELF,plex));
19149566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(*plex,P4EST_DIM));
19159566063dSJacob 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));
19169566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(*plex));
19170a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
19180a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
19190a96aa3bSJed Brown     sc_array_destroy (cones);
19200a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
19210a96aa3bSJed Brown     sc_array_destroy (coords);
19220a96aa3bSJed Brown     sc_array_destroy (children);
19230a96aa3bSJed Brown     sc_array_destroy (parents);
19240a96aa3bSJed Brown     sc_array_destroy (childids);
19250a96aa3bSJed Brown     sc_array_destroy (leaves);
19260a96aa3bSJed Brown     sc_array_destroy (remotes);
19270a96aa3bSJed Brown   }
19280a96aa3bSJed Brown   PetscFunctionReturn(0);
19290a96aa3bSJed Brown }
19300a96aa3bSJed Brown 
19310a96aa3bSJed Brown #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
19320a96aa3bSJed Brown static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB,PetscInt *childB)
19330a96aa3bSJed Brown {
19340a96aa3bSJed Brown   PetscInt       coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
19350a96aa3bSJed Brown 
19360a96aa3bSJed Brown   PetscFunctionBegin;
19370a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
19380a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
19390a96aa3bSJed Brown     if (childB) *childB = childA;
19400a96aa3bSJed Brown     PetscFunctionReturn(0);
19410a96aa3bSJed Brown   }
19429566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd));
19436aad120cSJose E. Roman   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invariant under rotation */
19440a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
19450a96aa3bSJed Brown     if (childB) *childB = childA;
19460a96aa3bSJed Brown     PetscFunctionReturn(0);
19470a96aa3bSJed Brown   }
19480a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
19499566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd));
19500a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
19510a96aa3bSJed Brown   }
195263a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %" PetscInt_FMT "-cells",dim);
195328b400f6SJacob Faibussowitsch   PetscCheck(dim,PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
19540a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
19550a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
19560a96aa3bSJed Brown     PetscInt       size, i, sA = -1, sB, sOrientB, sConeSize;
19570a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
19580a96aa3bSJed Brown 
19599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm,childA,&size));
19609566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm,childA,&supp));
19610a96aa3bSJed Brown 
19620a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
19630a96aa3bSJed Brown     for (i = 0; i < size; i++) {
19640a96aa3bSJed Brown       PetscInt sParent;
19650a96aa3bSJed Brown 
19660a96aa3bSJed Brown       sA = supp[i];
19670a96aa3bSJed Brown       if (sA == parent) continue;
19689566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,sA,&sParent,NULL));
19690a96aa3bSJed Brown       if (sParent == parent) break;
19700a96aa3bSJed Brown     }
197108401ef6SPierre Jolivet     PetscCheck(i != size,PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
19720a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
19730a96aa3bSJed Brown      * parentOrientB */
19749566063dSJacob Faibussowitsch     PetscCall(DMReferenceTreeGetChildSymmetry_pforest(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB));
19759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,sA,&sConeSize));
19769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sA,&coneA));
19779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sB,&coneB));
19789566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sA,&oA));
19799566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sB,&oB));
19800a96aa3bSJed Brown     /* step through the cone of sA in natural order */
19810a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
19820a96aa3bSJed Brown       if (coneA[i] == childA) {
19830a96aa3bSJed Brown         /* if childA is at position i in coneA,
19840a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
19850a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
19860a96aa3bSJed Brown         if (childB) *childB = coneB[j];
19870a96aa3bSJed Brown         if (childOrientB) {
19880a96aa3bSJed Brown           DMPolytopeType ct;
19890a96aa3bSJed Brown           PetscInt       oBtrue;
19900a96aa3bSJed Brown 
19919566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,childA,&coneSize));
19920a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
19931dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
19940a96aa3bSJed Brown           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
19950a96aa3bSJed Brown           /* we may have to flip an edge */
19960a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
19970a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
19980a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize,DMPolytopeConvertNewOrientation_Internal(ct, oA[i]),oBtrue);
19990a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
20000a96aa3bSJed Brown         }
20010a96aa3bSJed Brown         break;
20020a96aa3bSJed Brown       }
20030a96aa3bSJed Brown     }
200408401ef6SPierre Jolivet     PetscCheck(i != sConeSize,PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
20050a96aa3bSJed Brown     PetscFunctionReturn(0);
20060a96aa3bSJed Brown   }
20070a96aa3bSJed Brown   /* get the cone size and symmetry swap */
20089566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm,parent,&coneSize));
20090a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
20100a96aa3bSJed Brown   if (dim == 2) {
20110a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
20120a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
20130a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
20140a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
20150a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
20160a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
20170a96aa3bSJed Brown   } else {
20180a96aa3bSJed Brown     oAvert     = parentOrientA;
20190a96aa3bSJed Brown     oBvert     = parentOrientB;
20200a96aa3bSJed Brown     ABswapVert = ABswap;
20210a96aa3bSJed Brown   }
20220a96aa3bSJed Brown   if (childB) {
20230a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
20240a96aa3bSJed Brown     PetscInt       p, posA = -1, numChildren, i;
20250a96aa3bSJed Brown     const PetscInt *children;
20260a96aa3bSJed Brown 
20270a96aa3bSJed Brown     /* count which position the child is in */
20289566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm,parent,&numChildren,&children));
20290a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
20300a96aa3bSJed Brown       p = children[i];
20310a96aa3bSJed Brown       if (p == childA) {
20320a96aa3bSJed Brown         if (dim == 1) {
20330a96aa3bSJed Brown           posA = i;
20340a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
20350a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
20360a96aa3bSJed Brown         }
20370a96aa3bSJed Brown         break;
20380a96aa3bSJed Brown       }
20390a96aa3bSJed Brown     }
20400a96aa3bSJed Brown     if (posA >= coneSize) {
20410a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not find childA in children of parent");
20420a96aa3bSJed Brown     } else {
20430a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
20440a96aa3bSJed Brown       PetscInt posB, childIdB;
20450a96aa3bSJed Brown 
20460a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
20470a96aa3bSJed Brown       if (dim == 1) {
20480a96aa3bSJed Brown         childIdB = posB;
20490a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
20500a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
20510a96aa3bSJed Brown       }
20520a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
20530a96aa3bSJed Brown     }
20540a96aa3bSJed Brown   }
20550a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
20560a96aa3bSJed Brown   PetscFunctionReturn(0);
20570a96aa3bSJed Brown }
20580a96aa3bSJed Brown 
20590a96aa3bSJed Brown #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
20600a96aa3bSJed Brown static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm)
20610a96aa3bSJed Brown {
20620a96aa3bSJed Brown   p4est_connectivity_t *refcube;
20630a96aa3bSJed Brown   p4est_t              *root, *refined;
20640a96aa3bSJed Brown   DM                   dmRoot, dmRefined;
20650a96aa3bSJed Brown   DM_Plex              *mesh;
20660a96aa3bSJed Brown   PetscMPIInt          rank;
20670a96aa3bSJed Brown 
20680a96aa3bSJed Brown   PetscFunctionBegin;
20690a96aa3bSJed Brown   PetscStackCallP4estReturn(refcube,p4est_connectivity_new_byname,("unit"));
20700a96aa3bSJed Brown   { /* [-1,1]^d geometry */
20710a96aa3bSJed Brown     PetscInt i, j;
20720a96aa3bSJed Brown 
20730a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
20740a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
20750a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
20760a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
20770a96aa3bSJed Brown       }
20780a96aa3bSJed Brown     }
20790a96aa3bSJed Brown   }
20800a96aa3bSJed Brown   PetscStackCallP4estReturn(root,p4est_new,(PETSC_COMM_SELF,refcube,0,NULL,NULL));
20810a96aa3bSJed Brown   PetscStackCallP4estReturn(refined,p4est_new_ext,(PETSC_COMM_SELF,refcube,0,1,1,0,NULL,NULL));
20829566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(root,&dmRoot));
20839566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(refined,&dmRefined));
20840a96aa3bSJed Brown   {
20850a96aa3bSJed Brown #if !defined(P4_TO_P8)
20860a96aa3bSJed Brown     PetscInt nPoints  = 25;
20870a96aa3bSJed Brown     PetscInt perm[25] = {0, 1, 2, 3,
20880a96aa3bSJed Brown                           4, 12, 8, 14,
20890a96aa3bSJed Brown                               6, 9, 15,
20900a96aa3bSJed Brown                           5, 13,    10,
20910a96aa3bSJed Brown                               7,    11,
20920a96aa3bSJed Brown                          16, 22, 20, 24,
20930a96aa3bSJed Brown                              17,     21,
20940a96aa3bSJed Brown                                  18, 23,
20950a96aa3bSJed Brown                                      19};
20960a96aa3bSJed Brown     PetscInt ident[25] = {0, 0, 0, 0,
20970a96aa3bSJed Brown                           1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0,
20980a96aa3bSJed Brown                           5, 6, 7, 8, 1, 2, 3, 4, 0};
20990a96aa3bSJed Brown #else
21000a96aa3bSJed Brown     PetscInt nPoints   = 125;
21010a96aa3bSJed Brown     PetscInt perm[125] = {0, 1, 2, 3, 4, 5, 6, 7,
21020a96aa3bSJed Brown                            8, 32, 16, 36, 24, 40,
21030a96aa3bSJed Brown                               12, 17, 37, 25, 41,
21040a96aa3bSJed Brown                            9, 33,     20, 26, 42,
21050a96aa3bSJed Brown                               13,     21, 27, 43,
21060a96aa3bSJed Brown                           10, 34, 18, 38,     28,
21070a96aa3bSJed Brown                               14, 19, 39,     29,
21080a96aa3bSJed Brown                           11, 35,     22,     30,
21090a96aa3bSJed Brown                               15,     23,     31,
21100a96aa3bSJed Brown                           44, 84, 76, 92, 52, 86, 68, 94, 60, 78, 70, 96,
21110a96aa3bSJed Brown                           45, 85, 77, 93,     54,     72,     62,     74,
21120a96aa3bSJed Brown                               46,     80, 53, 87, 69, 95,         64, 82,
21130a96aa3bSJed Brown                               47,     81,     55,     73,             66,
21140a96aa3bSJed Brown                                   48, 88,         56, 90, 61, 79, 71, 97,
21150a96aa3bSJed Brown                                   49, 89,             58,     63,     75,
21160a96aa3bSJed Brown                                       50,         57, 91,         65, 83,
21170a96aa3bSJed Brown                                       51,             59,             67,
21180a96aa3bSJed Brown                            98, 106, 110, 122, 114, 120, 118, 124,
21190a96aa3bSJed Brown                                 99,      111,      115,      119,
21200a96aa3bSJed Brown                                     100, 107,           116, 121,
21210a96aa3bSJed Brown                                          101,                117,
21220a96aa3bSJed Brown                                               102, 108, 112, 123,
21230a96aa3bSJed Brown                                                    103,      113,
21240a96aa3bSJed Brown                                                         104, 109,
21250a96aa3bSJed Brown                                                              105};
21260a96aa3bSJed Brown     PetscInt ident[125] = {0, 0, 0, 0, 0, 0, 0, 0,
21270a96aa3bSJed Brown                            1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6,
21280a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21290a96aa3bSJed Brown                            7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18,
21300a96aa3bSJed Brown                            1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6,
21310a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0,
21320a96aa3bSJed Brown                            19, 20, 21, 22, 23, 24, 25, 26,
21330a96aa3bSJed Brown                            7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
21340a96aa3bSJed Brown                            1, 2, 3, 4, 5, 6,
21350a96aa3bSJed Brown                            0};
21360a96aa3bSJed Brown 
21370a96aa3bSJed Brown #endif
21380a96aa3bSJed Brown     IS permIS;
21390a96aa3bSJed Brown     DM dmPerm;
21400a96aa3bSJed Brown 
21419566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nPoints,perm,PETSC_USE_POINTER,&permIS));
21429566063dSJacob Faibussowitsch     PetscCall(DMPlexPermute(dmRefined,permIS,&dmPerm));
21430a96aa3bSJed Brown     if (dmPerm) {
21449566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmRefined));
21450a96aa3bSJed Brown       dmRefined = dmPerm;
21460a96aa3bSJed Brown     }
21479566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
21480a96aa3bSJed Brown     {
21490a96aa3bSJed Brown       PetscInt p;
21509566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRoot,"identity"));
21519566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRefined,"identity"));
21520a96aa3bSJed Brown       for (p = 0; p < P4EST_INSUL; p++) {
21539566063dSJacob Faibussowitsch         PetscCall(DMSetLabelValue(dmRoot,"identity",p,p));
21540a96aa3bSJed Brown       }
21550a96aa3bSJed Brown       for (p = 0; p < nPoints; p++) {
21569566063dSJacob Faibussowitsch         PetscCall(DMSetLabelValue(dmRefined,"identity",p,ident[p]));
21570a96aa3bSJed Brown       }
21580a96aa3bSJed Brown     }
21590a96aa3bSJed Brown   }
21609566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(dmRoot,dmRefined,"identity",dm));
21610a96aa3bSJed Brown   mesh                   = (DM_Plex*) (*dm)->data;
21620a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
21639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
21640a96aa3bSJed Brown   if (rank == 0) {
21659566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRoot,   NULL,"-dm_p4est_ref_root_view"));
21669566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_refined_view"));
21679566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_tree_view"));
21680a96aa3bSJed Brown   }
21699566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRefined));
21709566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRoot));
21710a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(refined));
21720a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(root));
21730a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,(refcube));
21740a96aa3bSJed Brown   PetscFunctionReturn(0);
21750a96aa3bSJed Brown }
21760a96aa3bSJed Brown 
21770a96aa3bSJed Brown static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB)
21780a96aa3bSJed Brown {
21790a96aa3bSJed Brown   void          *ctx;
21800a96aa3bSJed Brown   PetscInt       num;
21810a96aa3bSJed Brown   PetscReal      val;
21820a96aa3bSJed Brown 
21830a96aa3bSJed Brown   PetscFunctionBegin;
21849566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmA,&ctx));
21859566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dmB,ctx));
21869566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmA,dmB));
21879566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dmA,&num,&val));
21889566063dSJacob Faibussowitsch   PetscCall(DMSetOutputSequenceNumber(dmB,num,val));
21890a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
21909566063dSJacob Faibussowitsch     PetscCall(DMClearLocalVectors(dmB));
21919566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->localSection));
21929566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->localSection)));
21930a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
21949566063dSJacob Faibussowitsch     PetscCall(DMClearGlobalVectors(dmB));
21959566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->globalSection));
21969566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->globalSection)));
21970a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
21989566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.section));
21999566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->defaultConstraint.section)));
22003b8ba7d1SJed Brown     dmB->defaultConstraint.section = dmA->defaultConstraint.section;
22019566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.mat));
22029566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(dmB->defaultConstraint.mat)));
22033b8ba7d1SJed Brown     dmB->defaultConstraint.mat = dmA->defaultConstraint.mat;
22049566063dSJacob Faibussowitsch     if (dmA->map) PetscCall(PetscLayoutReference(dmA->map, &dmB->map));
22050a96aa3bSJed Brown   }
22060a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
22079566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->sectionSF));
22089566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&dmB->sectionSF));
22090a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
22100a96aa3bSJed Brown   }
22110a96aa3bSJed Brown   PetscFunctionReturn(0);
22120a96aa3bSJed Brown }
22130a96aa3bSJed Brown 
22140a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
22150a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm,p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF)
22160a96aa3bSJed Brown {
22170a96aa3bSJed Brown   PetscInt       startF, endF, startC, endC, p, nLeaves;
22180a96aa3bSJed Brown   PetscSFNode    *leaves;
22190a96aa3bSJed Brown   PetscSF        sf;
22200a96aa3bSJed Brown   PetscInt       *recv, *send;
22210a96aa3bSJed Brown   PetscMPIInt    tag;
22220a96aa3bSJed Brown   MPI_Request    *recvReqs, *sendReqs;
22230a96aa3bSJed Brown   PetscSection   section;
22240a96aa3bSJed Brown 
22250a96aa3bSJed Brown   PetscFunctionBegin;
22269566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estF,p4estC,&startC,&endC));
22279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2*(endC-startC),&recv,endC-startC,&recvReqs));
22289566063dSJacob Faibussowitsch   PetscCall(PetscCommGetNewTag(comm,&tag));
22290a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22300a96aa3bSJed Brown     recvReqs[p-startC] = MPI_REQUEST_NULL; /* just in case we don't initiate a receive */
22310a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p+1]) { /* empty coarse partition */
22320a96aa3bSJed Brown       recv[2*(p-startC)]   = 0;
22330a96aa3bSJed Brown       recv[2*(p-startC)+1] = 0;
22340a96aa3bSJed Brown       continue;
22350a96aa3bSJed Brown     }
22360a96aa3bSJed Brown 
22379566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(&recv[2*(p-startC)],2,MPIU_INT,p,tag,comm,&recvReqs[p-startC]));
22380a96aa3bSJed Brown   }
22399566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estC,p4estF,&startF,&endF));
22409566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2*(endF-startF),&send,endF-startF,&sendReqs));
22410a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
22420a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
22430a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
22440a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p+1];
22450a96aa3bSJed Brown     PetscInt         tStart       = (PetscInt) myFineStart->p.which_tree;
22460a96aa3bSJed Brown     PetscInt         tEnd         = (PetscInt) myFineEnd->p.which_tree;
22470a96aa3bSJed Brown     PetscInt         firstCell    = -1, lastCell = -1;
22480a96aa3bSJed Brown     p4est_tree_t     *treeStart   = &(((p4est_tree_t*) p4estC->trees->array)[tStart]);
22490a96aa3bSJed Brown     p4est_tree_t     *treeEnd     = (size_t) tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t*) p4estC->trees->array)[tEnd]) : NULL;
22500a96aa3bSJed Brown     ssize_t          overlapIndex;
22510a96aa3bSJed Brown 
22520a96aa3bSJed Brown     sendReqs[p-startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
22530a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p+1]) continue;
22540a96aa3bSJed Brown 
22550a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
22560a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
22570a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeStart->quadrants),myFineStart,p4est_quadrant_disjoint));
22580a96aa3bSJed Brown       if (overlapIndex < 0) {
22590a96aa3bSJed Brown         firstCell = 0;
22600a96aa3bSJed Brown       } else {
22610a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
22620a96aa3bSJed Brown       }
22630a96aa3bSJed Brown     } else {
22640a96aa3bSJed Brown       firstCell = 0;
22650a96aa3bSJed Brown     }
22660a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
22670a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeEnd->quadrants),myFineEnd,p4est_quadrant_disjoint));
22680a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
22690a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
22700a96aa3bSJed Brown       } else {
22710a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t*) treeEnd->quadrants.array)[overlapIndex]);
22720a96aa3bSJed Brown         p4est_quadrant_t first_desc;
22730a96aa3bSJed Brown         int              equal;
22740a96aa3bSJed Brown 
22750a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_first_descendant,(container,&first_desc,P4EST_QMAXLEVEL));
22760a96aa3bSJed Brown         PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(myFineEnd,&first_desc));
22770a96aa3bSJed Brown         if (equal) {
22780a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
22790a96aa3bSJed Brown         } else {
22800a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
22810a96aa3bSJed Brown         }
22820a96aa3bSJed Brown       }
22830a96aa3bSJed Brown     } else {
22840a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
22850a96aa3bSJed Brown     }
22860a96aa3bSJed Brown     send[2*(p-startF)]   = firstCell;
22870a96aa3bSJed Brown     send[2*(p-startF)+1] = lastCell - firstCell;
22889566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(&send[2*(p-startF)],2,MPIU_INT,p,tag,comm,&sendReqs[p-startF]));
22890a96aa3bSJed Brown   }
22909566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endC-startC),recvReqs,MPI_STATUSES_IGNORE));
22919566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&section));
22929566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section,startC,endC));
22930a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22940a96aa3bSJed Brown     PetscInt numCells = recv[2*(p-startC)+1];
22959566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section,p,numCells));
22960a96aa3bSJed Brown   }
22979566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
22989566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section,&nLeaves));
22999566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nLeaves,&leaves));
23000a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
23010a96aa3bSJed Brown     PetscInt firstCell = recv[2*(p-startC)];
23020a96aa3bSJed Brown     PetscInt numCells  = recv[2*(p-startC)+1];
23030a96aa3bSJed Brown     PetscInt off, i;
23040a96aa3bSJed Brown 
23059566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section,p,&off));
23060a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
23070a96aa3bSJed Brown       leaves[off+i].rank  = p;
23080a96aa3bSJed Brown       leaves[off+i].index = firstCell + i;
23090a96aa3bSJed Brown     }
23100a96aa3bSJed Brown   }
23119566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm,&sf));
23129566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf,cEnd-cStart,nLeaves,NULL,PETSC_OWN_POINTER,leaves,PETSC_OWN_POINTER));
23139566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
23149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endF-startF),sendReqs,MPI_STATUSES_IGNORE));
23159566063dSJacob Faibussowitsch   PetscCall(PetscFree2(send,sendReqs));
23169566063dSJacob Faibussowitsch   PetscCall(PetscFree2(recv,recvReqs));
23170a96aa3bSJed Brown   *coveringSF = sf;
23180a96aa3bSJed Brown   PetscFunctionReturn(0);
23190a96aa3bSJed Brown }
23200a96aa3bSJed Brown 
23210a96aa3bSJed Brown /* closure points for locally-owned cells */
23220a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints,PetscBool redirect)
23230a96aa3bSJed Brown {
23240a96aa3bSJed Brown   PetscInt          cStart, cEnd;
23250a96aa3bSJed Brown   PetscInt          count, c;
23260a96aa3bSJed Brown   PetscMPIInt       rank;
23270a96aa3bSJed Brown   PetscInt          closureSize = -1;
23280a96aa3bSJed Brown   PetscInt          *closure    = NULL;
23290a96aa3bSJed Brown   PetscSF           pointSF;
23300a96aa3bSJed Brown   PetscInt          nleaves, nroots;
23310a96aa3bSJed Brown   const PetscInt    *ilocal;
23320a96aa3bSJed Brown   const PetscSFNode *iremote;
23330a96aa3bSJed Brown   DM                plex;
23340a96aa3bSJed Brown   DM_Forest         *forest;
23350a96aa3bSJed Brown   DM_Forest_pforest *pforest;
23360a96aa3bSJed Brown 
23370a96aa3bSJed Brown   PetscFunctionBegin;
23380a96aa3bSJed Brown   forest            = (DM_Forest *) dm->data;
23390a96aa3bSJed Brown   pforest           = (DM_Forest_pforest *) forest->data;
23400a96aa3bSJed Brown   cStart            = pforest->cLocalStart;
23410a96aa3bSJed Brown   cEnd              = pforest->cLocalEnd;
23429566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
23439566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm,&pointSF));
23449566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(pointSF,&nroots,&nleaves,&ilocal,&iremote));
23450a96aa3bSJed Brown   nleaves           = PetscMax(0,nleaves);
23460a96aa3bSJed Brown   nroots            = PetscMax(0,nroots);
23470a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
23489566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numClosurePoints,closurePoints));
23499566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
23500a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
23510a96aa3bSJed Brown     PetscInt i;
23529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure));
23530a96aa3bSJed Brown 
23540a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
23550a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
23560a96aa3bSJed Brown       PetscInt loc = -1;
23570a96aa3bSJed Brown 
23589566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(p,nleaves,ilocal,&loc));
23590a96aa3bSJed Brown       if (redirect && loc >= 0) {
23600a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
23610a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
23620a96aa3bSJed Brown       } else {
23630a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
23640a96aa3bSJed Brown         (*closurePoints)[count].index = p;
23650a96aa3bSJed Brown       }
23660a96aa3bSJed Brown     }
23679566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure));
23680a96aa3bSJed Brown   }
23690a96aa3bSJed Brown   PetscFunctionReturn(0);
23700a96aa3bSJed Brown }
23710a96aa3bSJed Brown 
23720a96aa3bSJed Brown static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type)
23730a96aa3bSJed Brown {
23740a96aa3bSJed Brown   PetscMPIInt i;
23750a96aa3bSJed Brown 
23760a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
23770a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode*)a;
23780a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode*)b;
23790a96aa3bSJed Brown 
23800a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
23810a96aa3bSJed Brown   }
23820a96aa3bSJed Brown }
23830a96aa3bSJed Brown 
23840a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
23850a96aa3bSJed Brown {
23860a96aa3bSJed Brown   MPI_Comm          comm;
23870a96aa3bSJed Brown   PetscMPIInt       rank, size;
23880a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
23890a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
23900a96aa3bSJed Brown   PetscInt          numClosureIndices;
23910a96aa3bSJed Brown   PetscInt          numClosurePointsC, numClosurePointsF;
23920a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
23930a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
23940a96aa3bSJed Brown   p4est_quadrant_t  **treeQuads;
23950a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
23960a96aa3bSJed Brown   MPI_Datatype      nodeType;
23970a96aa3bSJed Brown   MPI_Datatype      nodeClosureType;
23980a96aa3bSJed Brown   MPI_Op            sfNodeReduce;
23990a96aa3bSJed Brown   p4est_topidx_t    fltF, lltF, t;
24000a96aa3bSJed Brown   DM                plexC, plexF;
24010a96aa3bSJed Brown   PetscInt          pStartF, pEndF, pStartC, pEndC;
24020a96aa3bSJed Brown   PetscBool         saveInCoarse = PETSC_FALSE;
24030a96aa3bSJed Brown   PetscBool         saveInFine   = PETSC_FALSE;
24040a96aa3bSJed Brown   PetscBool         formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
24050a96aa3bSJed Brown   PetscInt          *cids        = NULL;
24060a96aa3bSJed Brown 
24070a96aa3bSJed Brown   PetscFunctionBegin;
24080a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
24090a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
24100a96aa3bSJed Brown   p4estC   = pforestC->forest;
24110a96aa3bSJed Brown   p4estF   = pforestF->forest;
241208401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo,PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
24130a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
24149566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
24159566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm,&size));
24169566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine,&plexF));
24179566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF,&pStartF,&pEndF));
24189566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse,&plexC));
24199566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC,&pStartC,&pEndC));
24200a96aa3bSJed Brown   { /* check if the results have been cached */
24210a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
24220a96aa3bSJed Brown 
24239566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(coarse,&adaptCoarse));
24249566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(fine,&adaptFine));
24250a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
24260a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
24279566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestC->pointSelfToAdaptSF)));
24280a96aa3bSJed Brown         *sf  = pforestC->pointSelfToAdaptSF;
24290a96aa3bSJed Brown         if (childIds) {
24309566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
24319566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids,pforestC->pointSelfToAdaptCids,pEndF-pStartF));
24320a96aa3bSJed Brown           *childIds = cids;
24330a96aa3bSJed Brown         }
24340a96aa3bSJed Brown         PetscFunctionReturn(0);
24350a96aa3bSJed Brown       } else {
24360a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
24370a96aa3bSJed Brown         formCids     = PETSC_TRUE;
24380a96aa3bSJed Brown       }
24390a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
24400a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
24419566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestF->pointAdaptToSelfSF)));
24420a96aa3bSJed Brown         *sf  = pforestF->pointAdaptToSelfSF;
24430a96aa3bSJed Brown         if (childIds) {
24449566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
24459566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids,pforestF->pointAdaptToSelfCids,pEndF-pStartF));
24460a96aa3bSJed Brown           *childIds = cids;
24470a96aa3bSJed Brown         }
24480a96aa3bSJed Brown         PetscFunctionReturn(0);
24490a96aa3bSJed Brown       } else {
24500a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
24510a96aa3bSJed Brown         formCids   = PETSC_TRUE;
24520a96aa3bSJed Brown       }
24530a96aa3bSJed Brown     }
24540a96aa3bSJed Brown   }
24550a96aa3bSJed Brown 
24560a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
24570a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
24580a96aa3bSJed Brown   /* create the datatype */
24599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(2,MPIU_INT,&nodeType));
24609566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
24619566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_create(DMPforestMaxSFNode,PETSC_FALSE,&sfNodeReduce));
24629566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(numClosureIndices*2,MPIU_INT,&nodeClosureType));
24639566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeClosureType));
24640a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
24650a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
24669566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(coarse,numClosureIndices,&numClosurePointsC,&closurePointsC,PETSC_TRUE));
24679566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(fine  ,numClosureIndices,&numClosurePointsF,&closurePointsF,PETSC_FALSE));
24680a96aa3bSJed Brown   /* create pointers for tree lists */
24690a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
24700a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
24719566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(lltF + 1  - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts));
24720a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
24730a96aa3bSJed Brown   if (size > 1) {
24740a96aa3bSJed Brown     PetscInt p;
24750a96aa3bSJed Brown 
24760a96aa3bSJed Brown     for (p = 0; p < size; p++) {
24770a96aa3bSJed Brown       int equal;
24780a96aa3bSJed Brown 
24790a96aa3bSJed Brown       PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal_piggy,(&p4estC->global_first_position[p],&p4estF->global_first_position[p]));
24800a96aa3bSJed Brown       if (!equal) break;
24810a96aa3bSJed Brown     }
24820a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
24830a96aa3bSJed Brown       PetscInt         cStartC, cEndC;
24840a96aa3bSJed Brown       PetscSF          coveringSF;
24850a96aa3bSJed Brown       PetscInt         nleaves;
24860a96aa3bSJed Brown       PetscInt         count;
24870a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
24880a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
24890a96aa3bSJed Brown       p4est_topidx_t   fltC = p4estC->first_local_tree;
24900a96aa3bSJed Brown       p4est_topidx_t   lltC = p4estC->last_local_tree;
24910a96aa3bSJed Brown       p4est_topidx_t   t;
24920a96aa3bSJed Brown       PetscMPIInt      blockSizes[4]   = {P4EST_DIM,2,1,1};
24930a96aa3bSJed Brown       MPI_Aint         blockOffsets[4] = {offsetof(p4est_quadrant_t,x),
24940a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,level),
24950a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,pad16),
24960a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,p)};
24970a96aa3bSJed Brown       MPI_Datatype     blockTypes[4] = {MPI_INT32_T,MPI_INT8_T,MPI_INT16_T,MPI_INT32_T/* p.which_tree */};
24980a96aa3bSJed Brown       MPI_Datatype     quadStruct,quadType;
24990a96aa3bSJed Brown 
25009566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC,0,&cStartC,&cEndC));
25019566063dSJacob Faibussowitsch       PetscCall(DMPforestGetCellCoveringSF(comm,p4estC,p4estF,pforestC->cLocalStart,pforestC->cLocalEnd,&coveringSF));
25029566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coveringSF,NULL,&nleaves,NULL,NULL));
25039566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numClosureIndices*nleaves,&newClosurePointsC));
25049566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&coverQuads));
25059566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cEndC-cStartC,&coverQuadsSend));
25060a96aa3bSJed Brown       count = 0;
25070a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
25080a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
25090a96aa3bSJed Brown         PetscInt     q;
25100a96aa3bSJed Brown 
25119566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&coverQuadsSend[count],tree->quadrants.array,tree->quadrants.elem_count * sizeof(p4est_quadrant_t)));
25120a96aa3bSJed Brown         for (q = 0; (size_t) q < tree->quadrants.elem_count; q++) coverQuadsSend[count+q].p.which_tree = t;
25130a96aa3bSJed Brown         count += tree->quadrants.elem_count;
25140a96aa3bSJed Brown       }
25150a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
25160a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
25170a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
25180a96aa3bSJed Brown        */
25199566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_struct(4,blockSizes,blockOffsets,blockTypes,&quadStruct));
25209566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_resized(quadStruct,0,sizeof(p4est_quadrant_t),&quadType));
25219566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&quadType));
25229566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE));
25239566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE));
25249566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE));
25259566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE));
25269566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadStruct));
25279566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadType));
25289566063dSJacob Faibussowitsch       PetscCall(PetscFree(coverQuadsSend));
25299566063dSJacob Faibussowitsch       PetscCall(PetscFree(closurePointsC));
25309566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coveringSF));
25310a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
25320a96aa3bSJed Brown 
25330a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
25340a96aa3bSJed Brown       {
25350a96aa3bSJed Brown         PetscInt q;
25360a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
25370a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
25380a96aa3bSJed Brown           if (!treeQuadCounts[t-fltF]++) treeQuads[t-fltF] = &coverQuads[q];
25390a96aa3bSJed Brown         }
25400a96aa3bSJed Brown       }
25410a96aa3bSJed Brown     }
25420a96aa3bSJed Brown   }
25430a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
25440a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
25450a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
25460a96aa3bSJed Brown 
25470a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
25480a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t*) tree->quadrants.array;
25490a96aa3bSJed Brown     }
25500a96aa3bSJed Brown   }
25510a96aa3bSJed Brown 
25520a96aa3bSJed Brown   {
25530a96aa3bSJed Brown     PetscInt    p;
25540a96aa3bSJed Brown     PetscInt    cLocalStartF;
25550a96aa3bSJed Brown     PetscSF     pointSF;
25560a96aa3bSJed Brown     PetscSFNode *roots;
25570a96aa3bSJed Brown     PetscInt    *rootType;
25580a96aa3bSJed Brown     DM          refTree = NULL;
25590a96aa3bSJed Brown     DMLabel     canonical;
25600a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
25610a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
25620a96aa3bSJed Brown     PetscInt    coarseOffset;
25630a96aa3bSJed Brown     PetscInt    numCoarseQuads;
25640a96aa3bSJed Brown 
25659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF-pStartF,&roots));
25669566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF-pStartF,&rootType));
25679566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(fine,&pointSF));
25680a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
25690a96aa3bSJed Brown       roots[p-pStartF].rank  = -1;
25700a96aa3bSJed Brown       roots[p-pStartF].index = -1;
25710a96aa3bSJed Brown       rootType[p-pStartF]    = -1;
25720a96aa3bSJed Brown     }
25730a96aa3bSJed Brown     if (formCids) {
25740a96aa3bSJed Brown       PetscInt child;
25750a96aa3bSJed Brown 
25769566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
25770a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
25789566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF,&refTree));
25799566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure));
25800a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
25819566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]));
25820a96aa3bSJed Brown       }
25839566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(refTree,"canonical",&canonical));
25840a96aa3bSJed Brown     }
25850a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
25860a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
25870a96aa3bSJed Brown       p4est_tree_t     *tree        = &(((p4est_tree_t*) p4estF->trees->array)[t]);
25880a96aa3bSJed Brown       PetscInt         numFineQuads = tree->quadrants.elem_count;
25890a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads = treeQuads[t - fltF];
25900a96aa3bSJed Brown       p4est_quadrant_t *fineQuads   = (p4est_quadrant_t*) tree->quadrants.array;
25910a96aa3bSJed Brown       PetscInt         i, coarseCount = 0;
25920a96aa3bSJed Brown       PetscInt         offset = tree->quadrants_offset;
25930a96aa3bSJed Brown       sc_array_t       coarseQuadsArray;
25940a96aa3bSJed Brown 
25950a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
25960a96aa3bSJed Brown       PetscStackCallP4est(sc_array_init_data,(&coarseQuadsArray,coarseQuads,sizeof(p4est_quadrant_t),(size_t) numCoarseQuads));
25970a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
25980a96aa3bSJed Brown         PetscInt         c     = i + offset;
25990a96aa3bSJed Brown         p4est_quadrant_t *quad = &fineQuads[i];
26000a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
26010a96aa3bSJed Brown         ssize_t          disjoint = -1;
26020a96aa3bSJed Brown 
26030a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
26040a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
26050a96aa3bSJed Brown           PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
26060a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
26070a96aa3bSJed Brown         }
260808401ef6SPierre Jolivet         PetscCheck(disjoint == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"did not find overlapping coarse quad");
26090a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
26100a96aa3bSJed Brown           if (transferIdent) { /* find corners */
26110a96aa3bSJed Brown             PetscInt j = 0;
26120a96aa3bSJed Brown 
26130a96aa3bSJed Brown             do {
26140a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
26150a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
26160a96aa3bSJed Brown                 int              equal;
26170a96aa3bSJed Brown 
26180a96aa3bSJed Brown                 PetscStackCallP4est(p4est_quadrant_corner_descendant,(quad,&cornerQuad,j,quadCoarse->level));
26190a96aa3bSJed Brown                 PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(&cornerQuad,quadCoarse));
26200a96aa3bSJed Brown                 if (equal) {
26210a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
26220a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
26230a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
26240a96aa3bSJed Brown 
26250a96aa3bSJed Brown                   roots[p-pStartF]    = q;
26260a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
26270a96aa3bSJed Brown                   cids[p-pStartF]     = -1;
26280a96aa3bSJed Brown                   j++;
26290a96aa3bSJed Brown                 }
26300a96aa3bSJed Brown               }
26310a96aa3bSJed Brown               coarseCount++;
26320a96aa3bSJed Brown               disjoint = 1;
26330a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
26340a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
26350a96aa3bSJed Brown                 PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
26360a96aa3bSJed Brown               }
26370a96aa3bSJed Brown             } while (!disjoint);
26380a96aa3bSJed Brown           }
26390a96aa3bSJed Brown           continue;
26400a96aa3bSJed Brown         }
26410a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
26420a96aa3bSJed Brown           PetscInt j;
26430a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
26440a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
26450a96aa3bSJed Brown 
26460a96aa3bSJed Brown             roots[p-pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
26470a96aa3bSJed Brown             rootType[p-pStartF] = PETSC_MAX_INT; /* unconditionally accept */
26480a96aa3bSJed Brown             cids[p-pStartF]     = -1;
26490a96aa3bSJed Brown           }
26500a96aa3bSJed Brown         } else {
26510a96aa3bSJed Brown           PetscInt levelDiff = quad->level - quadCoarse->level;
26520a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
26530a96aa3bSJed Brown 
26540a96aa3bSJed Brown           if (formCids) {
26550a96aa3bSJed Brown             PetscInt cl;
26560a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
26570a96aa3bSJed Brown             int      cid;
26580a96aa3bSJed Brown 
265908401ef6SPierre Jolivet             PetscCheck(levelDiff <= 1,PETSC_COMM_SELF,PETSC_ERR_USER,"Recursive child ids not implemented");
26600a96aa3bSJed Brown             PetscStackCallP4estReturn(cid,p4est_quadrant_child_id,(quad));
26619566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure));
26620a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
26630a96aa3bSJed Brown               PetscInt p      = pointClosure[2 * cl];
26640a96aa3bSJed Brown               PetscInt point  = childClosures[cid][2 * cl];
26650a96aa3bSJed Brown               PetscInt ornt   = childClosures[cid][2 * cl + 1];
26660a96aa3bSJed Brown               PetscInt newcid = -1;
26670a96aa3bSJed Brown               DMPolytopeType ct;
26680a96aa3bSJed Brown 
26690a96aa3bSJed Brown               if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
26709566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCellType(refTree, point, &ct));
26710a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
26720a96aa3bSJed Brown               if (!cl) {
26730a96aa3bSJed Brown                 newcid = cid + 1;
26740a96aa3bSJed Brown               } else {
26750a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
26760a96aa3bSJed Brown 
26779566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetTreeParent(refTree,point,&parent,NULL));
26780a96aa3bSJed Brown                 if (parent == point) {
26790a96aa3bSJed Brown                   newcid = -1;
26800a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
26810a96aa3bSJed Brown                   newcid = point;
26820a96aa3bSJed Brown                 } else {
26830a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
26840a96aa3bSJed Brown 
26850a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
26860a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
26879566063dSJacob Faibussowitsch                       PetscCall(DMPlexGetCellType(refTree, parent, &rct));
26880a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
26890a96aa3bSJed Brown                       break;
26900a96aa3bSJed Brown                     }
26910a96aa3bSJed Brown                   }
269208401ef6SPierre Jolivet                   PetscCheck(rcl < P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Couldn't find parent in root closure");
26939566063dSJacob Faibussowitsch                   PetscCall(DMPlexReferenceTreeGetChildSymmetry(refTree,parent,parentOrnt,ornt,point,DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]),NULL,&newcid));
26940a96aa3bSJed Brown                 }
26950a96aa3bSJed Brown               }
26960a96aa3bSJed Brown               if (newcid >= 0) {
26970a96aa3bSJed Brown 
26980a96aa3bSJed Brown                 if (canonical) {
26999566063dSJacob Faibussowitsch                   PetscCall(DMLabelGetValue(canonical,newcid,&newcid));
27000a96aa3bSJed Brown                 }
27010a96aa3bSJed Brown                 proposedCids[cl] = newcid;
27020a96aa3bSJed Brown               }
27030a96aa3bSJed Brown             }
27049566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure));
27050a96aa3bSJed Brown           }
27060a96aa3bSJed Brown           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {{quadCoarse->x,quadCoarse->y,
27070a96aa3bSJed Brown #if defined(P4_TO_P8)
27080a96aa3bSJed Brown                                                        quadCoarse->z
27090a96aa3bSJed Brown #endif
27100a96aa3bSJed Brown                                                       },{0}};
27110a96aa3bSJed Brown           p4est_qcoord_t fineBound[2][P4EST_DIM] = {{quad->x,quad->y,
27120a96aa3bSJed Brown #if defined(P4_TO_P8)
27130a96aa3bSJed Brown                                                      quad->z
27140a96aa3bSJed Brown #endif
27150a96aa3bSJed Brown                                                     },{0}};
27160a96aa3bSJed Brown           PetscInt       j;
27170a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
27180a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
27190a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j]   + P4EST_QUADRANT_LEN(quad->level);
27200a96aa3bSJed Brown           }
27210a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
27220a96aa3bSJed Brown             PetscInt    l, p;
27230a96aa3bSJed Brown             PetscSFNode q;
27240a96aa3bSJed Brown 
27250a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
27260a96aa3bSJed Brown             if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
27270a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
27280a96aa3bSJed Brown               l = 0;
27290a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
27300a96aa3bSJed Brown               PetscInt face = PetscFaceToP4estFace[j - 1];
27310a96aa3bSJed Brown               PetscInt direction = face / 2;
27320a96aa3bSJed Brown               PetscInt coarseFace = -1;
27330a96aa3bSJed Brown 
27340a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
27350a96aa3bSJed Brown                 coarseFace = face;
27360a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27370a96aa3bSJed Brown               } else {
27380a96aa3bSJed Brown                 l = 0;
27390a96aa3bSJed Brown               }
27400a96aa3bSJed Brown #if defined(P4_TO_P8)
27410a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
27420a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
27430a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
27440a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
27450a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
27460a96aa3bSJed Brown               PetscInt  minDir     = PetscMin((direction + 1) % 3,(direction + 2) % 3);
27470a96aa3bSJed Brown               PetscInt  maxDir     = PetscMax((direction + 1) % 3,(direction + 2) % 3);
27480a96aa3bSJed Brown               PetscBool dirTest[2];
27490a96aa3bSJed Brown 
27500a96aa3bSJed Brown               dirTest[0] = (PetscBool) (coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
27510a96aa3bSJed Brown               dirTest[1] = (PetscBool) (coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
27520a96aa3bSJed Brown 
27530a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
27540a96aa3bSJed Brown                 coarseEdge = edge;
27550a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27560a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
27570a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
27580a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27590a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
27600a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
27610a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27620a96aa3bSJed Brown               } else {
27630a96aa3bSJed Brown                 l = 0;
27640a96aa3bSJed Brown               }
27650a96aa3bSJed Brown #endif
27660a96aa3bSJed Brown             } else {
27670a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
27680a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
27690a96aa3bSJed Brown               PetscInt  m;
27700a96aa3bSJed Brown               PetscInt  numMatch     = 0;
27710a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
27720a96aa3bSJed Brown #if defined(P4_TO_P8)
27730a96aa3bSJed Brown               PetscInt coarseEdge = -1;
27740a96aa3bSJed Brown #endif
27750a96aa3bSJed Brown 
27760a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
27770a96aa3bSJed Brown                 dirTest[m] = (PetscBool) (coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
27780a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
27790a96aa3bSJed Brown               }
27800a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
27810a96aa3bSJed Brown                 coarseVertex = vertex;
27820a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
27830a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
27840a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27850a96aa3bSJed Brown                   if (dirTest[m]) {
27860a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
27870a96aa3bSJed Brown                     break;
27880a96aa3bSJed Brown                   }
27890a96aa3bSJed Brown                 }
27900a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27910a96aa3bSJed Brown #if defined(P4_TO_P8)
27920a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
27930a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27940a96aa3bSJed Brown                   if (!dirTest[m]) {
27950a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
27960a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
27970a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1,otherDir2);
27980a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1,otherDir2);
27990a96aa3bSJed Brown 
28000a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
28010a96aa3bSJed Brown                     break;
28020a96aa3bSJed Brown                   }
28030a96aa3bSJed Brown                 }
28040a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
28050a96aa3bSJed Brown #endif
28060a96aa3bSJed Brown               } else { /* volume */
28070a96aa3bSJed Brown                 l = 0;
28080a96aa3bSJed Brown               }
28090a96aa3bSJed Brown             }
28100a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
28110a96aa3bSJed Brown             if (l > rootType[p-pStartF]) {
28120a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
28130a96aa3bSJed Brown                 if (transferIdent) {
28140a96aa3bSJed Brown                   roots[p-pStartF] = q;
28150a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
28160a96aa3bSJed Brown                   if (formCids) cids[p-pStartF] = -1;
28170a96aa3bSJed Brown                 }
28180a96aa3bSJed Brown               } else {
28190a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
28200a96aa3bSJed Brown 
28210a96aa3bSJed Brown                 roots[p-pStartF] = q;
28220a96aa3bSJed Brown                 rootType[p-pStartF] = l;
28230a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
28240a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
28250a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
28260a96aa3bSJed Brown                   PetscInt parent;
28270a96aa3bSJed Brown 
28289566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetTreeParent(plexF,thisp,&parent,NULL));
28290a96aa3bSJed Brown                   if (parent == thisp) break;
28300a96aa3bSJed Brown 
28310a96aa3bSJed Brown                   roots[parent-pStartF] = q;
28320a96aa3bSJed Brown                   rootType[parent-pStartF] = PETSC_MAX_INT;
28330a96aa3bSJed Brown                   if (formCids) cids[parent-pStartF] = -1;
28340a96aa3bSJed Brown                   thisp = parent;
28350a96aa3bSJed Brown                 }
28360a96aa3bSJed Brown               }
28370a96aa3bSJed Brown             }
28380a96aa3bSJed Brown           }
28390a96aa3bSJed Brown         }
28400a96aa3bSJed Brown       }
28410a96aa3bSJed Brown     }
28420a96aa3bSJed Brown 
28430a96aa3bSJed 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 */
28440a96aa3bSJed Brown     if (size > 1) {
28450a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
28460a96aa3bSJed Brown 
28479566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&rootTypeCopy));
28489566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(rootTypeCopy,rootType,pEndF-pStartF));
28499566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX));
28509566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX));
28519566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE));
28529566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE));
28530a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28540a96aa3bSJed 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 */
28550a96aa3bSJed Brown           roots[p-pStartF].rank  = -1;
28560a96aa3bSJed Brown           roots[p-pStartF].index = -1;
28570a96aa3bSJed Brown         }
28580a96aa3bSJed Brown         if (formCids && rootTypeCopy[p-pStartF] == PETSC_MAX_INT) {
28590a96aa3bSJed Brown           cids[p-pStartF] = -1; /* we have found an antecedent that is the same: no child id */
28600a96aa3bSJed Brown         }
28610a96aa3bSJed Brown       }
28629566063dSJacob Faibussowitsch       PetscCall(PetscFree(rootTypeCopy));
28639566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,nodeType,roots,roots,sfNodeReduce));
28649566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,nodeType,roots,roots,sfNodeReduce));
28659566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,nodeType,roots,roots,MPI_REPLACE));
28669566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,nodeType,roots,roots,MPI_REPLACE));
28670a96aa3bSJed Brown     }
28689566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootType));
28690a96aa3bSJed Brown 
28700a96aa3bSJed Brown     {
28710a96aa3bSJed Brown       PetscInt    numRoots;
28720a96aa3bSJed Brown       PetscInt    numLeaves;
28730a96aa3bSJed Brown       PetscInt    *leaves;
28740a96aa3bSJed Brown       PetscSFNode *iremote;
28750a96aa3bSJed Brown       /* count leaves */
28760a96aa3bSJed Brown 
28770a96aa3bSJed Brown       numRoots = pEndC - pStartC;
28780a96aa3bSJed Brown 
28790a96aa3bSJed Brown       numLeaves = 0;
28800a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28810a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) numLeaves++;
28820a96aa3bSJed Brown       }
28839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves,&leaves));
28849566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves,&iremote));
28850a96aa3bSJed Brown       numLeaves = 0;
28860a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28870a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) {
28880a96aa3bSJed Brown           leaves[numLeaves]  = p-pStartF;
28890a96aa3bSJed Brown           iremote[numLeaves] = roots[p-pStartF];
28900a96aa3bSJed Brown           numLeaves++;
28910a96aa3bSJed Brown         }
28920a96aa3bSJed Brown       }
28939566063dSJacob Faibussowitsch       PetscCall(PetscFree(roots));
28949566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm,sf));
28950a96aa3bSJed Brown       if (numLeaves == (pEndF-pStartF)) {
28969566063dSJacob Faibussowitsch         PetscCall(PetscFree(leaves));
28979566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
28980a96aa3bSJed Brown       } else {
28999566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf,numRoots,numLeaves,leaves,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
29000a96aa3bSJed Brown       }
29010a96aa3bSJed Brown     }
29020a96aa3bSJed Brown     if (formCids) {
29030a96aa3bSJed Brown       PetscSF  pointSF;
29040a96aa3bSJed Brown       PetscInt child;
29050a96aa3bSJed Brown 
29069566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF,&refTree));
29079566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(plexF,&pointSF));
29089566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,cids,cids,MPIU_MAX));
29099566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,cids,cids,MPIU_MAX));
29100a96aa3bSJed Brown       if (childIds) *childIds = cids;
29110a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) {
29129566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]));
29130a96aa3bSJed Brown       }
29149566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure));
29150a96aa3bSJed Brown     }
29160a96aa3bSJed Brown   }
29170a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
29189566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
29190a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
29200a96aa3bSJed Brown     if (!childIds) {
29210a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
29220a96aa3bSJed Brown     } else {
29239566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&pforestC->pointSelfToAdaptCids));
29249566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestC->pointSelfToAdaptCids,cids,pEndF-pStartF));
29250a96aa3bSJed Brown     }
29260a96aa3bSJed Brown   } else if (saveInFine) {
29279566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
29280a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
29290a96aa3bSJed Brown     if (!childIds) {
29300a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
29310a96aa3bSJed Brown     } else {
29329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&pforestF->pointAdaptToSelfCids));
29339566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestF->pointAdaptToSelfCids,cids,pEndF-pStartF));
29340a96aa3bSJed Brown     }
29350a96aa3bSJed Brown   }
29369566063dSJacob Faibussowitsch   PetscCall(PetscFree2(treeQuads,treeQuadCounts));
29379566063dSJacob Faibussowitsch   PetscCall(PetscFree(coverQuads));
29389566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsC));
29399566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsF));
29409566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeClosureType));
29419566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_free(&sfNodeReduce));
29429566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
29430a96aa3bSJed Brown   PetscFunctionReturn(0);
29440a96aa3bSJed Brown }
29450a96aa3bSJed Brown 
29460a96aa3bSJed Brown /* children are sf leaves of parents */
29470a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
29480a96aa3bSJed Brown {
29490a96aa3bSJed Brown   MPI_Comm          comm;
2950d70f29a3SPierre Jolivet   PetscMPIInt       rank;
29510a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
29520a96aa3bSJed Brown   DM                plexC, plexF;
29530a96aa3bSJed Brown   PetscInt          pStartC, pEndC, pStartF, pEndF;
29540a96aa3bSJed Brown   PetscSF           pointTransferSF;
29550a96aa3bSJed Brown   PetscBool         allOnes = PETSC_TRUE;
29560a96aa3bSJed Brown 
29570a96aa3bSJed Brown   PetscFunctionBegin;
29580a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
29590a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
296008401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo,PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
29610a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
29629566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
29630a96aa3bSJed Brown 
29640a96aa3bSJed Brown   {
29650a96aa3bSJed Brown     PetscInt i;
29660a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
29670a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
29680a96aa3bSJed Brown         allOnes = PETSC_FALSE;
29690a96aa3bSJed Brown         break;
29700a96aa3bSJed Brown       }
29710a96aa3bSJed Brown     }
29720a96aa3bSJed Brown   }
29739566063dSJacob Faibussowitsch   PetscCall(DMPforestGetTransferSF_Point(coarse,fine,&pointTransferSF,transferIdent,childIds));
29740a96aa3bSJed Brown   if (allOnes) {
29750a96aa3bSJed Brown     *sf = pointTransferSF;
29760a96aa3bSJed Brown     PetscFunctionReturn(0);
29770a96aa3bSJed Brown   }
29780a96aa3bSJed Brown 
29799566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine,&plexF));
29809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF,&pStartF,&pEndF));
29819566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse,&plexC));
29829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC,&pStartC,&pEndC));
29830a96aa3bSJed Brown   {
29840a96aa3bSJed Brown     PetscInt          numRoots;
29850a96aa3bSJed Brown     PetscInt          numLeaves;
29860a96aa3bSJed Brown     const PetscInt    *leaves;
29870a96aa3bSJed Brown     const PetscSFNode *iremote;
29880a96aa3bSJed Brown     PetscInt          d;
29890a96aa3bSJed Brown     PetscSection      leafSection, rootSection;
29900a96aa3bSJed Brown     /* count leaves */
29910a96aa3bSJed Brown 
29929566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointTransferSF,&numRoots,&numLeaves,&leaves,&iremote));
29939566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&rootSection));
29949566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&leafSection));
29959566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(rootSection,pStartC,pEndC));
29969566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(leafSection,pStartF,pEndF));
29970a96aa3bSJed Brown 
29980a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
29990a96aa3bSJed Brown       PetscInt startC, endC, e;
30000a96aa3bSJed Brown 
30019566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC,P4EST_DIM-d,&startC,&endC));
30020a96aa3bSJed Brown       for (e = startC; e < endC; e++) {
30039566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(rootSection,e,dofPerDim[d]));
30040a96aa3bSJed Brown       }
30050a96aa3bSJed Brown     }
30060a96aa3bSJed Brown 
30070a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
30080a96aa3bSJed Brown       PetscInt startF, endF, e;
30090a96aa3bSJed Brown 
30109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexF,P4EST_DIM-d,&startF,&endF));
30110a96aa3bSJed Brown       for (e = startF; e < endF; e++) {
30129566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafSection,e,dofPerDim[d]));
30130a96aa3bSJed Brown       }
30140a96aa3bSJed Brown     }
30150a96aa3bSJed Brown 
30169566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(rootSection));
30179566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafSection));
30180a96aa3bSJed Brown     {
30190a96aa3bSJed Brown       PetscInt    nroots, nleaves;
30200a96aa3bSJed Brown       PetscInt    *mine, i, p;
30210a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
30220a96aa3bSJed Brown       PetscSFNode *remote;
30230a96aa3bSJed Brown 
30249566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&offsets));
30259566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndC-pStartC,&offsetsRoot));
30260a96aa3bSJed Brown       for (p = pStartC; p < pEndC; p++) {
30279566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootSection,p,&offsetsRoot[p-pStartC]));
30280a96aa3bSJed Brown       }
30299566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE));
30309566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE));
30319566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(rootSection,&nroots));
30320a96aa3bSJed Brown       nleaves = 0;
30330a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
30340a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
30350a96aa3bSJed Brown         PetscInt dof;
30360a96aa3bSJed Brown 
30379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection,leaf,&dof));
30380a96aa3bSJed Brown         nleaves += dof;
30390a96aa3bSJed Brown       }
30409566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&mine));
30419566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&remote));
30420a96aa3bSJed Brown       nleaves = 0;
30430a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
30440a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
30450a96aa3bSJed Brown         PetscInt dof;
30460a96aa3bSJed Brown         PetscInt off, j;
30470a96aa3bSJed Brown 
30489566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection,leaf,&dof));
30499566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafSection,leaf,&off));
30500a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
30510a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
30520a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
30530a96aa3bSJed Brown           mine[nleaves++]       = off + j;
30540a96aa3bSJed Brown         }
30550a96aa3bSJed Brown       }
30569566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsetsRoot));
30579566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsets));
30589566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm,sf));
30599566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(*sf,nroots,nleaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
30600a96aa3bSJed Brown     }
30619566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
30629566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootSection));
30639566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointTransferSF));
30640a96aa3bSJed Brown   }
30650a96aa3bSJed Brown   PetscFunctionReturn(0);
30660a96aa3bSJed Brown }
30670a96aa3bSJed Brown 
30680a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA)
30690a96aa3bSJed Brown {
30700a96aa3bSJed Brown   DM             adaptA, adaptB;
30710a96aa3bSJed Brown   DMAdaptFlag    purpose;
30720a96aa3bSJed Brown 
30730a96aa3bSJed Brown   PetscFunctionBegin;
30749566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmA,&adaptA));
30759566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmB,&adaptB));
30760a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
30770a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
30789566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmA,&purpose));
30790a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
30809566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30810a96aa3bSJed Brown       PetscFunctionReturn(0);
30820a96aa3bSJed Brown     }
30830a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
30849566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmB,&purpose));
30850a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
30869566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30870a96aa3bSJed Brown       PetscFunctionReturn(0);
30880a96aa3bSJed Brown     }
30890a96aa3bSJed Brown   }
3090*1baa6e33SBarry Smith   if (sfAtoB) PetscCall(DMPforestGetTransferSF_Internal(dmA,dmB,dofPerDim,sfAtoB,PETSC_TRUE,NULL));
3091*1baa6e33SBarry Smith   if (sfBtoA) PetscCall(DMPforestGetTransferSF_Internal(dmB,dmA,dofPerDim,sfBtoA,(PetscBool) (sfAtoB == NULL),NULL));
30920a96aa3bSJed Brown   PetscFunctionReturn(0);
30930a96aa3bSJed Brown }
30940a96aa3bSJed Brown 
30950a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex)
30960a96aa3bSJed Brown {
30970a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
30980a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
30990a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
31000a96aa3bSJed Brown   PetscInt          cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
31010a96aa3bSJed Brown   PetscInt          pStart, pEnd, pStartBase, pEndBase, p;
31020a96aa3bSJed Brown   DM                base;
31030a96aa3bSJed Brown   PetscInt          *star     = NULL, starSize;
31040a96aa3bSJed Brown   DMLabelLink       next      = dm->labels;
31050a96aa3bSJed Brown   PetscInt          guess     = 0;
31060a96aa3bSJed Brown   p4est_topidx_t    num_trees = pforest->topo->conn->num_trees;
31070a96aa3bSJed Brown 
31080a96aa3bSJed Brown   PetscFunctionBegin;
31090a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
31100a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
31110a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
31129566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
31130a96aa3bSJed Brown   if (!base) {
31140a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
31150a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
31160a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
31170a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t*) p4est->trees->array;
31180a96aa3bSJed Brown       p4est_topidx_t       t, flt = p4est->first_local_tree;
31190a96aa3bSJed Brown       p4est_topidx_t       llt = pforest->forest->last_local_tree;
31200a96aa3bSJed Brown       DMLabel              ghostLabel;
31210a96aa3bSJed Brown       PetscInt             c;
31220a96aa3bSJed Brown 
31239566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(plex,pforest->ghostName));
31249566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(plex,pforest->ghostName,&ghostLabel));
31250a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
31260a96aa3bSJed Brown         p4est_tree_t     *tree    = &trees[t];
31270a96aa3bSJed Brown         p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
31280a96aa3bSJed Brown         PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
31290a96aa3bSJed Brown         PetscInt         q;
31300a96aa3bSJed Brown 
31310a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
31320a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
31330a96aa3bSJed Brown           PetscInt         f;
31340a96aa3bSJed Brown 
31350a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
31360a96aa3bSJed Brown             p4est_quadrant_t neigh;
31370a96aa3bSJed Brown             int              isOutside;
31380a96aa3bSJed Brown 
31390a96aa3bSJed Brown             PetscStackCallP4est(p4est_quadrant_face_neighbor,(quad,f,&neigh));
31400a96aa3bSJed Brown             PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&neigh));
31410a96aa3bSJed Brown             if (isOutside) {
31420a96aa3bSJed Brown               p4est_topidx_t nt;
31430a96aa3bSJed Brown               PetscInt       nf;
31440a96aa3bSJed Brown 
31450a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
31460a96aa3bSJed Brown               nf = (PetscInt) conn->tree_to_face[t * P4EST_FACES + f];
31470a96aa3bSJed Brown               nf = nf % P4EST_FACES;
31480a96aa3bSJed Brown               if (nt == t && nf == f) {
31490a96aa3bSJed Brown                 PetscInt       plexF = P4estFaceToPetscFace[f];
31500a96aa3bSJed Brown                 const PetscInt *cone;
31510a96aa3bSJed Brown 
31529566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetCone(plex,c,&cone));
31539566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(ghostLabel,cone[plexF],plexF+1));
31540a96aa3bSJed Brown               }
31550a96aa3bSJed Brown             }
31560a96aa3bSJed Brown           }
31570a96aa3bSJed Brown         }
31580a96aa3bSJed Brown       }
31590a96aa3bSJed Brown     }
31600a96aa3bSJed Brown     PetscFunctionReturn(0);
31610a96aa3bSJed Brown   }
31629566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,0,&cStartBase,&cEndBase));
31639566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,1,&fStartBase,&fEndBase));
31649566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,P4EST_DIM-1,&eStartBase,&eEndBase));
31659566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase));
31660a96aa3bSJed Brown 
31679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,0,&cStart,&cEnd));
31689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,1,&fStart,&fEnd));
31699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,P4EST_DIM-1,&eStart,&eEnd));
31709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex,0,&vStart,&vEnd));
31710a96aa3bSJed Brown 
31729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex,&pStart,&pEnd));
31739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(base,&pStartBase,&pEndBase));
31740a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
31750a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
31760a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
31770a96aa3bSJed Brown   while (next) {
31780a96aa3bSJed Brown     DMLabel   baseLabel;
31790a96aa3bSJed Brown     DMLabel   label = next->label;
31800a96aa3bSJed Brown     PetscBool isDepth, isCellType, isGhost, isVTK, isSpmap;
31810a96aa3bSJed Brown     const char *name;
31820a96aa3bSJed Brown 
31839566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) label, &name));
31849566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"depth",&isDepth));
31850a96aa3bSJed Brown     if (isDepth) {
31860a96aa3bSJed Brown       next = next->next;
31870a96aa3bSJed Brown       continue;
31880a96aa3bSJed Brown     }
31899566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"celltype",&isCellType));
31900a96aa3bSJed Brown     if (isCellType) {
31910a96aa3bSJed Brown       next = next->next;
31920a96aa3bSJed Brown       continue;
31930a96aa3bSJed Brown     }
31949566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"ghost",&isGhost));
31950a96aa3bSJed Brown     if (isGhost) {
31960a96aa3bSJed Brown       next = next->next;
31970a96aa3bSJed Brown       continue;
31980a96aa3bSJed Brown     }
31999566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"vtk",&isVTK));
32000a96aa3bSJed Brown     if (isVTK) {
32010a96aa3bSJed Brown       next = next->next;
32020a96aa3bSJed Brown       continue;
32030a96aa3bSJed Brown     }
32049566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"_forest_base_subpoint_map",&isSpmap));
32050a96aa3bSJed Brown     if (!isSpmap) {
32069566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(base,name,&baseLabel));
32070a96aa3bSJed Brown       if (!baseLabel) {
32080a96aa3bSJed Brown         next = next->next;
32090a96aa3bSJed Brown         continue;
32100a96aa3bSJed Brown       }
32119566063dSJacob Faibussowitsch       PetscCall(DMLabelCreateIndex(baseLabel,pStartBase,pEndBase));
32120a96aa3bSJed Brown     } else baseLabel = NULL;
32130a96aa3bSJed Brown 
32140a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
32150a96aa3bSJed Brown       PetscInt         s, c = -1, l;
32160a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
32170a96aa3bSJed Brown       p4est_quadrant_t * ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
32180a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t*) pforest->forest->trees->array;
32190a96aa3bSJed Brown       p4est_quadrant_t * q;
32200a96aa3bSJed Brown       PetscInt         t, val;
32210a96aa3bSJed Brown       PetscBool        zerosupportpoint = PETSC_FALSE;
32220a96aa3bSJed Brown 
32239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
32240a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
32250a96aa3bSJed Brown         PetscInt point = star[2*s];
32260a96aa3bSJed Brown 
32270a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
32289566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(plex,point,PETSC_TRUE,&closureSize,&closure));
32290a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
32300a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
32310a96aa3bSJed Brown             do { /* check parents of q */
32320a96aa3bSJed Brown               q = qParent;
32330a96aa3bSJed Brown               if (q == p) {
32340a96aa3bSJed Brown                 c = point;
32350a96aa3bSJed Brown                 break;
32360a96aa3bSJed Brown               }
32379566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex,q,&qParent,NULL));
32380a96aa3bSJed Brown             } while (qParent != q);
32390a96aa3bSJed Brown             if (c != -1) break;
32409566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(plex,pp,&pParent,NULL));
32410a96aa3bSJed Brown             q = closure[2 * l];
32420a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
32430a96aa3bSJed Brown               pp = pParent;
32440a96aa3bSJed Brown               if (pp == q) {
32450a96aa3bSJed Brown                 c = point;
32460a96aa3bSJed Brown                 break;
32470a96aa3bSJed Brown               }
32489566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex,pp,&pParent,NULL));
32490a96aa3bSJed Brown             }
32500a96aa3bSJed Brown             if (c != -1) break;
32510a96aa3bSJed Brown           }
32529566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(plex,point,PETSC_TRUE,NULL,&closure));
32530a96aa3bSJed Brown           if (l < closureSize) break;
32540a96aa3bSJed Brown         } else {
32550a96aa3bSJed Brown           PetscInt supportSize;
32560a96aa3bSJed Brown 
32579566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(plex,point,&supportSize));
32580a96aa3bSJed Brown           zerosupportpoint = (PetscBool) (zerosupportpoint || !supportSize);
32590a96aa3bSJed Brown         }
32600a96aa3bSJed Brown       }
32610a96aa3bSJed Brown       if (c < 0) {
32620a96aa3bSJed Brown         const char* prefix;
32630a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
32640a96aa3bSJed Brown 
32659566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
32669566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_forest_print_label_error",&print,NULL));
32670a96aa3bSJed Brown         if (print) {
32680a96aa3bSJed Brown           PetscInt i;
32690a96aa3bSJed Brown 
327063a3b9bcSJacob 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));
327163a3b9bcSJacob 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]));
32720a96aa3bSJed Brown         }
32739566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star));
32740a96aa3bSJed Brown         if (zerosupportpoint) continue;
327563a3b9bcSJacob Faibussowitsch         else 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");
32760a96aa3bSJed Brown       }
32779566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star));
32780a96aa3bSJed Brown 
32790a96aa3bSJed Brown       if (c < cLocalStart) {
32800a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
32810a96aa3bSJed Brown         q = &(ghosts[c]);
32820a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
32830a96aa3bSJed Brown       } else if (c < cLocalEnd) {
32840a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
32850a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
32860a96aa3bSJed Brown 
32870a96aa3bSJed Brown         c -= cLocalStart;
32880a96aa3bSJed Brown 
32890a96aa3bSJed Brown         do {
32900a96aa3bSJed Brown           p4est_tree_t *tree;
32910a96aa3bSJed Brown 
32921dca8a05SBarry Smith           PetscCheck(guess >= lo && guess < num_trees && lo < hi,PETSC_COMM_SELF,PETSC_ERR_PLIB,"failed binary search");
32930a96aa3bSJed Brown           tree = &trees[guess];
32940a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
32950a96aa3bSJed Brown             hi = guess;
32960a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt) tree->quadrants.elem_count) {
32970a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt) tree->quadrants_offset];
32980a96aa3bSJed Brown             t = guess;
32990a96aa3bSJed Brown             break;
33000a96aa3bSJed Brown           } else {
33010a96aa3bSJed Brown             lo = guess + 1;
33020a96aa3bSJed Brown           }
33030a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
33040a96aa3bSJed Brown         } while (1);
33050a96aa3bSJed Brown       } else {
33060a96aa3bSJed Brown         /* get from the end of the ghost layer */
33070a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
33080a96aa3bSJed Brown 
33090a96aa3bSJed Brown         q = &(ghosts[c]);
33100a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
33110a96aa3bSJed Brown       }
33120a96aa3bSJed Brown 
33130a96aa3bSJed Brown       if (l == 0) { /* cell */
33140a96aa3bSJed Brown         if (baseLabel) {
33159566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33160a96aa3bSJed Brown         } else {
33170a96aa3bSJed Brown           val  = t+cStartBase;
33180a96aa3bSJed Brown         }
33199566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label,p,val));
33200a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
33210a96aa3bSJed Brown         p4est_quadrant_t nq;
33220a96aa3bSJed Brown         int              isInside;
33230a96aa3bSJed Brown 
33240a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
33250a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_face_neighbor,(q,l,&nq));
33260a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
33270a96aa3bSJed Brown         if (isInside) {
33280a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
33290a96aa3bSJed Brown           if (baseLabel) {
33309566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33310a96aa3bSJed Brown           } else {
33320a96aa3bSJed Brown             val  = t+cStartBase;
33330a96aa3bSJed Brown           }
33349566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33350a96aa3bSJed Brown         } else {
33360a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
33370a96aa3bSJed Brown 
33380a96aa3bSJed Brown           if (baseLabel) {
33399566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
33400a96aa3bSJed Brown           } else {
33410a96aa3bSJed Brown             val  = f+fStartBase;
33420a96aa3bSJed Brown           }
33439566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33440a96aa3bSJed Brown         }
33450a96aa3bSJed Brown #if defined(P4_TO_P8)
33460a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
33470a96aa3bSJed Brown         p4est_quadrant_t nq;
33480a96aa3bSJed Brown         int              isInside;
33490a96aa3bSJed Brown 
33500a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
33510a96aa3bSJed Brown         PetscStackCallP4est(p8est_quadrant_edge_neighbor,(q,l,&nq));
33520a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
33530a96aa3bSJed Brown         if (isInside) {
33540a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
33550a96aa3bSJed Brown           if (baseLabel) {
33569566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33570a96aa3bSJed Brown           } else {
33580a96aa3bSJed Brown             val  = t+cStartBase;
33590a96aa3bSJed Brown           }
33609566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33610a96aa3bSJed Brown         } else {
33620a96aa3bSJed Brown           int isOutsideFace;
33630a96aa3bSJed Brown 
33640a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutsideFace,p4est_quadrant_is_outside_face,(&nq));
33650a96aa3bSJed Brown           if (isOutsideFace) {
33660a96aa3bSJed Brown             PetscInt f;
33670a96aa3bSJed Brown 
33680a96aa3bSJed Brown             if (nq.x < 0) {
33690a96aa3bSJed Brown               f = 0;
33700a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33710a96aa3bSJed Brown               f = 1;
33720a96aa3bSJed Brown             } else if (nq.y < 0) {
33730a96aa3bSJed Brown               f = 2;
33740a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33750a96aa3bSJed Brown               f = 3;
33760a96aa3bSJed Brown             } else if (nq.z < 0) {
33770a96aa3bSJed Brown               f = 4;
33780a96aa3bSJed Brown             } else {
33790a96aa3bSJed Brown               f = 5;
33800a96aa3bSJed Brown             }
33810a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33820a96aa3bSJed Brown             if (baseLabel) {
33839566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
33840a96aa3bSJed Brown             } else {
33850a96aa3bSJed Brown               val  = f+fStartBase;
33860a96aa3bSJed Brown             }
33879566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
33880a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
33890a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
33900a96aa3bSJed Brown 
33910a96aa3bSJed Brown             if (baseLabel) {
33929566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,e+eStartBase,&val));
33930a96aa3bSJed Brown             } else {
33940a96aa3bSJed Brown               val  = e+eStartBase;
33950a96aa3bSJed Brown             }
33969566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
33970a96aa3bSJed Brown           }
33980a96aa3bSJed Brown         }
33990a96aa3bSJed Brown #endif
34000a96aa3bSJed Brown       } else { /* vertex */
34010a96aa3bSJed Brown         p4est_quadrant_t nq;
34020a96aa3bSJed Brown         int              isInside;
34030a96aa3bSJed Brown 
34040a96aa3bSJed Brown #if defined(P4_TO_P8)
34050a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
34060a96aa3bSJed Brown #else
34070a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
34080a96aa3bSJed Brown #endif
34090a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_corner_neighbor,(q,l,&nq));
34100a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
34110a96aa3bSJed Brown         if (isInside) {
34120a96aa3bSJed Brown           if (baseLabel) {
34139566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
34140a96aa3bSJed Brown           } else {
34150a96aa3bSJed Brown             val  = t+cStartBase;
34160a96aa3bSJed Brown           }
34179566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
34180a96aa3bSJed Brown         } else {
34190a96aa3bSJed Brown           int isOutside;
34200a96aa3bSJed Brown 
34210a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&nq));
34220a96aa3bSJed Brown           if (isOutside) {
34230a96aa3bSJed Brown             PetscInt f = -1;
34240a96aa3bSJed Brown 
34250a96aa3bSJed Brown             if (nq.x < 0) {
34260a96aa3bSJed Brown               f = 0;
34270a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
34280a96aa3bSJed Brown               f = 1;
34290a96aa3bSJed Brown             } else if (nq.y < 0) {
34300a96aa3bSJed Brown               f = 2;
34310a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
34320a96aa3bSJed Brown               f = 3;
34330a96aa3bSJed Brown #if defined(P4_TO_P8)
34340a96aa3bSJed Brown             } else if (nq.z < 0) {
34350a96aa3bSJed Brown               f = 4;
34360a96aa3bSJed Brown             } else {
34370a96aa3bSJed Brown               f = 5;
34380a96aa3bSJed Brown #endif
34390a96aa3bSJed Brown             }
34400a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
34410a96aa3bSJed Brown             if (baseLabel) {
34429566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
34430a96aa3bSJed Brown             } else {
34440a96aa3bSJed Brown               val  = f+fStartBase;
34450a96aa3bSJed Brown             }
34469566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
34470a96aa3bSJed Brown             continue;
34480a96aa3bSJed Brown           }
34490a96aa3bSJed Brown #if defined(P4_TO_P8)
34500a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p8est_quadrant_is_outside_edge,(&nq));
34510a96aa3bSJed Brown           if (isOutside) {
34520a96aa3bSJed Brown             /* outside edge */
34530a96aa3bSJed Brown             PetscInt e = -1;
34540a96aa3bSJed Brown 
34550a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
34560a96aa3bSJed Brown               if (nq.z < 0) {
34570a96aa3bSJed Brown                 if (nq.y < 0) {
34580a96aa3bSJed Brown                   e = 0;
34590a96aa3bSJed Brown                 } else {
34600a96aa3bSJed Brown                   e = 1;
34610a96aa3bSJed Brown                 }
34620a96aa3bSJed Brown               } else {
34630a96aa3bSJed Brown                 if (nq.y < 0) {
34640a96aa3bSJed Brown                   e = 2;
34650a96aa3bSJed Brown                 } else {
34660a96aa3bSJed Brown                   e = 3;
34670a96aa3bSJed Brown                 }
34680a96aa3bSJed Brown               }
34690a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
34700a96aa3bSJed Brown               if (nq.z < 0) {
34710a96aa3bSJed Brown                 if (nq.x < 0) {
34720a96aa3bSJed Brown                   e = 4;
34730a96aa3bSJed Brown                 } else {
34740a96aa3bSJed Brown                   e = 5;
34750a96aa3bSJed Brown                 }
34760a96aa3bSJed Brown               } else {
34770a96aa3bSJed Brown                 if (nq.x < 0) {
34780a96aa3bSJed Brown                   e = 6;
34790a96aa3bSJed Brown                 } else {
34800a96aa3bSJed Brown                   e = 7;
34810a96aa3bSJed Brown                 }
34820a96aa3bSJed Brown               }
34830a96aa3bSJed Brown             } else {
34840a96aa3bSJed Brown               if (nq.y < 0) {
34850a96aa3bSJed Brown                 if (nq.x < 0) {
34860a96aa3bSJed Brown                   e = 8;
34870a96aa3bSJed Brown                 } else {
34880a96aa3bSJed Brown                   e = 9;
34890a96aa3bSJed Brown                 }
34900a96aa3bSJed Brown               } else {
34910a96aa3bSJed Brown                 if (nq.x < 0) {
34920a96aa3bSJed Brown                   e = 10;
34930a96aa3bSJed Brown                 } else {
34940a96aa3bSJed Brown                   e = 11;
34950a96aa3bSJed Brown                 }
34960a96aa3bSJed Brown               }
34970a96aa3bSJed Brown             }
34980a96aa3bSJed Brown 
34990a96aa3bSJed Brown             e    = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
35000a96aa3bSJed Brown             if (baseLabel) {
35019566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,e+eStartBase,&val));
35020a96aa3bSJed Brown             } else {
35030a96aa3bSJed Brown               val  = e+eStartBase;
35040a96aa3bSJed Brown             }
35059566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
35060a96aa3bSJed Brown             continue;
35070a96aa3bSJed Brown           }
35080a96aa3bSJed Brown #endif
35090a96aa3bSJed Brown           {
35100a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
35110a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
35120a96aa3bSJed Brown 
35130a96aa3bSJed Brown             if (baseLabel) {
35149566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,v+vStartBase,&val));
35150a96aa3bSJed Brown             } else {
35160a96aa3bSJed Brown               val  = v+vStartBase;
35170a96aa3bSJed Brown             }
35189566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
35190a96aa3bSJed Brown           }
35200a96aa3bSJed Brown         }
35210a96aa3bSJed Brown       }
35220a96aa3bSJed Brown     }
35230a96aa3bSJed Brown     next = next->next;
35240a96aa3bSJed Brown   }
35250a96aa3bSJed Brown   PetscFunctionReturn(0);
35260a96aa3bSJed Brown }
35270a96aa3bSJed Brown 
35280a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex)
35290a96aa3bSJed Brown {
35300a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
35310a96aa3bSJed Brown   DM                adapt;
35320a96aa3bSJed Brown 
35330a96aa3bSJed Brown   PetscFunctionBegin;
35340a96aa3bSJed Brown   if (pforest->labelsFinalized) PetscFunctionReturn(0);
35350a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
35369566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm,&adapt));
35370a96aa3bSJed Brown   if (!adapt) {
35380a96aa3bSJed Brown     /* Initialize labels from the base dm */
35399566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsInitialize(dm,plex));
35400a96aa3bSJed Brown   } else {
35410a96aa3bSJed Brown     PetscInt    dofPerDim[4]={1, 1, 1, 1};
35420a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
35430a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
35440a96aa3bSJed Brown     PetscInt    *values, *adaptValues;
35450a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
35460a96aa3bSJed Brown     DMLabel     adaptLabel;
35470a96aa3bSJed Brown     DM          adaptPlex;
35480a96aa3bSJed Brown 
35499566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm,&adaptLabel));
35509566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(adapt,&adaptPlex));
35519566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF(adapt,dm,dofPerDim,&transferForward,&transferBackward));
35529566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex,&pStart,&pEnd));
35539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(adaptPlex,&pStartA,&pEndA));
35549566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEnd-pStart,&values,pEndA-pStartA,&adaptValues));
35559566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex,&pointSF));
35560a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
35570a96aa3bSJed Brown       PetscInt p;
35580a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p-pStartA] = -1;
35590a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++)   values[p-pStart]       = -2;
35600a96aa3bSJed Brown       if (transferForward) {
35619566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
35629566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
35630a96aa3bSJed Brown       }
35640a96aa3bSJed Brown       if (transferBackward) {
35659566063dSJacob Faibussowitsch         PetscCall(PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
35669566063dSJacob Faibussowitsch         PetscCall(PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
35670a96aa3bSJed Brown       }
35680a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35690a96aa3bSJed Brown         PetscInt q = p, parent;
35700a96aa3bSJed Brown 
35719566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
35720a96aa3bSJed Brown         while (parent != q) {
35730a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
35740a96aa3bSJed Brown           q    = parent;
35759566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
35760a96aa3bSJed Brown         }
35770a96aa3bSJed Brown       }
35789566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX));
35799566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX));
35809566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE));
35819566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE));
35820a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
358363a3b9bcSJacob Faibussowitsch         PetscCheck(values[p-pStart] != -2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"uncovered point %" PetscInt_FMT,p);
35840a96aa3bSJed Brown       }
35850a96aa3bSJed Brown     }
35860a96aa3bSJed Brown     while (next) {
35870a96aa3bSJed Brown       DMLabel    nextLabel = next->label;
35880a96aa3bSJed Brown       const char *name;
35890a96aa3bSJed Brown       PetscBool  isDepth, isCellType, isGhost, isVTK;
35900a96aa3bSJed Brown       DMLabel    label;
35910a96aa3bSJed Brown       PetscInt   p;
35920a96aa3bSJed Brown 
35939566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject) nextLabel, &name));
35949566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"depth",&isDepth));
35950a96aa3bSJed Brown       if (isDepth) {
35960a96aa3bSJed Brown         next = next->next;
35970a96aa3bSJed Brown         continue;
35980a96aa3bSJed Brown       }
35999566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"celltype",&isCellType));
36000a96aa3bSJed Brown       if (isCellType) {
36010a96aa3bSJed Brown         next = next->next;
36020a96aa3bSJed Brown         continue;
36030a96aa3bSJed Brown       }
36049566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"ghost",&isGhost));
36050a96aa3bSJed Brown       if (isGhost) {
36060a96aa3bSJed Brown         next = next->next;
36070a96aa3bSJed Brown         continue;
36080a96aa3bSJed Brown       }
36099566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"vtk",&isVTK));
36100a96aa3bSJed Brown       if (isVTK) {
36110a96aa3bSJed Brown         next = next->next;
36120a96aa3bSJed Brown         continue;
36130a96aa3bSJed Brown       }
36140a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
36150a96aa3bSJed Brown         next = next->next;
36160a96aa3bSJed Brown         continue;
36170a96aa3bSJed Brown       }
36180a96aa3bSJed Brown       /* label was created earlier */
36199566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm,name,&label));
36200a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) {
36219566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(nextLabel,p,&adaptValues[p]));
36220a96aa3bSJed Brown       }
36230a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
36240a96aa3bSJed Brown 
3625*1baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
3626*1baa6e33SBarry Smith       if (transferBackward) PetscCall(PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
3627*1baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
3628*1baa6e33SBarry Smith       if (transferBackward) PetscCall(PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
36290a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
36300a96aa3bSJed Brown         PetscInt q = p, parent;
36310a96aa3bSJed Brown 
36329566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
36330a96aa3bSJed Brown         while (parent != q) {
36340a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
36350a96aa3bSJed Brown           q    = parent;
36369566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
36370a96aa3bSJed Brown         }
36380a96aa3bSJed Brown       }
36399566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX));
36409566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX));
36419566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE));
36429566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE));
36430a96aa3bSJed Brown 
36440a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
36459566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label,p,values[p]));
36460a96aa3bSJed Brown       }
36470a96aa3bSJed Brown       next = next->next;
36480a96aa3bSJed Brown     }
36499566063dSJacob Faibussowitsch     PetscCall(PetscFree2(values,adaptValues));
36509566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferForward));
36519566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferBackward));
36520a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
36530a96aa3bSJed Brown   }
36540a96aa3bSJed Brown   PetscFunctionReturn(0);
36550a96aa3bSJed Brown }
36560a96aa3bSJed Brown 
36570a96aa3bSJed Brown 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)
36580a96aa3bSJed Brown {
36590a96aa3bSJed Brown   PetscInt       closureSize, c, coordStart, coordEnd, coordDim;
36600a96aa3bSJed Brown   PetscInt       *closure = NULL;
36610a96aa3bSJed Brown   PetscSection   coordSec;
36620a96aa3bSJed Brown 
36630a96aa3bSJed Brown   PetscFunctionBegin;
36649566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex,&coordSec));
36659566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSec,&coordStart,&coordEnd));
36669566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(plex,&coordDim));
36679566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure));
36680a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
36690a96aa3bSJed Brown     PetscInt point = closure[2 * c];
36700a96aa3bSJed Brown 
36710a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
36720a96aa3bSJed Brown       PetscInt dof, off;
36730a96aa3bSJed Brown       PetscInt nCoords, i;
36749566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec,point,&dof));
367508401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
36760a96aa3bSJed Brown       nCoords = dof / coordDim;
36779566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec,point,&off));
36780a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
36790a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
36800a96aa3bSJed Brown         double      coordP4est[3]       = {0.};
36810a96aa3bSJed Brown         double      coordP4estMapped[3] = {0.};
36820a96aa3bSJed Brown         PetscInt    j;
36830a96aa3bSJed Brown         PetscReal   treeCoords[P4EST_CHILDREN][3] = {{0.}};
36840a96aa3bSJed Brown         PetscReal   eta[3]                        = {0.};
36850a96aa3bSJed Brown         PetscInt    numRounds                     = 10;
36860a96aa3bSJed Brown         PetscReal   coordGuess[3]                 = {0.};
36870a96aa3bSJed Brown 
36880a96aa3bSJed Brown         eta[0] = (PetscReal) q->x / (PetscReal) P4EST_ROOT_LEN;
36890a96aa3bSJed Brown         eta[1] = (PetscReal) q->y / (PetscReal) P4EST_ROOT_LEN;
36900a96aa3bSJed Brown #if defined(P4_TO_P8)
36910a96aa3bSJed Brown         eta[2] = (PetscReal) q->z / (PetscReal) P4EST_ROOT_LEN;
36920a96aa3bSJed Brown #endif
36930a96aa3bSJed Brown 
36940a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
36950a96aa3bSJed Brown           PetscInt k;
36960a96aa3bSJed Brown 
36970a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
36980a96aa3bSJed Brown         }
36990a96aa3bSJed Brown 
37000a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
37010a96aa3bSJed Brown           PetscInt  k;
37020a96aa3bSJed Brown           PetscReal prod = 1.;
37030a96aa3bSJed Brown 
37040a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
37050a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
37060a96aa3bSJed Brown         }
37070a96aa3bSJed Brown 
37080a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
37090a96aa3bSJed Brown           PetscInt dir;
37100a96aa3bSJed Brown 
37110a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
37120a96aa3bSJed Brown             PetscInt  k;
37130a96aa3bSJed Brown             PetscReal diff[3];
37140a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
37150a96aa3bSJed Brown             PetscReal rhs, scale, update;
37160a96aa3bSJed Brown 
37170a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
37180a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
37190a96aa3bSJed Brown               PetscInt  l;
37200a96aa3bSJed Brown               PetscReal prod = 1.;
37210a96aa3bSJed Brown 
37220a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
37230a96aa3bSJed Brown                 if (l == dir) {
37240a96aa3bSJed Brown                   prod *= (k & (1 << l)) ?  1. : -1.;
37250a96aa3bSJed Brown                 } else {
37260a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
37270a96aa3bSJed Brown                 }
37280a96aa3bSJed Brown               }
37290a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
37300a96aa3bSJed Brown             }
37310a96aa3bSJed Brown             rhs   = 0.;
37320a96aa3bSJed Brown             scale = 0;
37330a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
37340a96aa3bSJed Brown               rhs   += diff[k] * dXdeta[k];
37350a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
37360a96aa3bSJed Brown             }
37370a96aa3bSJed Brown             update    = rhs / scale;
37380a96aa3bSJed Brown             eta[dir] += update;
37390a96aa3bSJed Brown             eta[dir]  = PetscMin(eta[dir],1.);
37400a96aa3bSJed Brown             eta[dir]  = PetscMax(eta[dir],0.);
37410a96aa3bSJed Brown 
37420a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
37430a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
37440a96aa3bSJed Brown               PetscInt  l;
37450a96aa3bSJed Brown               PetscReal prod = 1.;
37460a96aa3bSJed Brown 
37470a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
37480a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
37490a96aa3bSJed Brown             }
37500a96aa3bSJed Brown           }
37510a96aa3bSJed Brown         }
37520a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double) eta[j];
37530a96aa3bSJed Brown 
37540a96aa3bSJed Brown         if (geom) {
37550a96aa3bSJed Brown           (geom->X)(geom,t,coordP4est,coordP4estMapped);
37560a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
37570a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not coded");
37580a96aa3bSJed Brown       }
37590a96aa3bSJed Brown     }
37600a96aa3bSJed Brown   }
37619566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure));
37620a96aa3bSJed Brown   PetscFunctionReturn(0);
37630a96aa3bSJed Brown }
37640a96aa3bSJed Brown 
37650a96aa3bSJed Brown static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex)
37660a96aa3bSJed Brown {
37670a96aa3bSJed Brown   DM_Forest         *forest;
37680a96aa3bSJed Brown   DM_Forest_pforest *pforest;
37690a96aa3bSJed Brown   p4est_geometry_t  *geom;
37700a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd;
37710a96aa3bSJed Brown   Vec               coordLocalVec;
37720a96aa3bSJed Brown   PetscScalar       *coords;
37730a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
37740a96aa3bSJed Brown   p4est_tree_t      *trees;
37750a96aa3bSJed Brown   PetscErrorCode    (*map)(DM,PetscInt, PetscInt, const PetscReal [], PetscReal [], void*);
37760a96aa3bSJed Brown   void              *mapCtx;
37770a96aa3bSJed Brown 
37780a96aa3bSJed Brown   PetscFunctionBegin;
37790a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
37800a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
37810a96aa3bSJed Brown   geom    = pforest->topo->geom;
37829566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx));
37830a96aa3bSJed Brown   if (!geom && !map) PetscFunctionReturn(0);
37849566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex,&coordLocalVec));
37859566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordLocalVec,&coords));
37860a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
37870a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
37880a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
37890a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
37900a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
37910a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
37920a96aa3bSJed Brown     PetscSection coordSec;
37930a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
37940a96aa3bSJed Brown     DM           base;
37950a96aa3bSJed Brown 
37969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
37979566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
37980a96aa3bSJed Brown     cEnd          = cEndInterior < 0 ? cEnd : cEndInterior;
37999566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm,&base));
38009566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(plex,&coordSec));
38019566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(coordSec,&coordStart,&coordEnd));
38029566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(plex,&coordDim));
38030a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim,3);
38040a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
38050a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
38060a96aa3bSJed Brown       PetscInt dof, off, cell = -1, coarsePoint = -1;
38070a96aa3bSJed Brown       PetscInt nCoords, i;
38089566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec,p,&dof));
380908401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
38100a96aa3bSJed Brown       nCoords = dof / coordDim;
38119566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec,p,&off));
38129566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
38130a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
38140a96aa3bSJed Brown         PetscInt point = star[2 * i];
38150a96aa3bSJed Brown 
38160a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
38170a96aa3bSJed Brown           cell = point;
38180a96aa3bSJed Brown           break;
38190a96aa3bSJed Brown         }
38200a96aa3bSJed Brown       }
38219566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
38220a96aa3bSJed Brown       if (cell >= 0) {
38230a96aa3bSJed Brown         if (cell < cLocalStart) {
38240a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38250a96aa3bSJed Brown 
38260a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
38270a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
38280a96aa3bSJed Brown           cell -= cLocalStart;
38290a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
38300a96aa3bSJed Brown             p4est_tree_t *tree = &(trees[t]);
38310a96aa3bSJed Brown 
38320a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t) cell < tree->quadrants_offset + tree->quadrants.elem_count) {
38330a96aa3bSJed Brown               coarsePoint = t;
38340a96aa3bSJed Brown               break;
38350a96aa3bSJed Brown             }
38360a96aa3bSJed Brown           }
38370a96aa3bSJed Brown         } else {
38380a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38390a96aa3bSJed Brown 
38400a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
38410a96aa3bSJed Brown         }
38420a96aa3bSJed Brown       }
38430a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
38440a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
38450a96aa3bSJed Brown         PetscReal   coordP4est[3]       = {0.};
38460a96aa3bSJed Brown         PetscReal   coordP4estMapped[3] = {0.};
38470a96aa3bSJed Brown         PetscInt    j;
38480a96aa3bSJed Brown 
38490a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
38509566063dSJacob Faibussowitsch         PetscCall((map)(base,coarsePoint,p4estCoordDim,coordP4est,coordP4estMapped,mapCtx));
38510a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
38520a96aa3bSJed Brown       }
38530a96aa3bSJed Brown     }
38540a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
38550a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
38560a96aa3bSJed Brown 
38579566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
38589566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
38590a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
38600a96aa3bSJed Brown     if (cLocalStart > 0) {
38610a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38620a96aa3bSJed Brown       PetscInt         count;
38630a96aa3bSJed Brown 
38640a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
38650a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
38660a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
38670a96aa3bSJed Brown 
38689566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count,quad,t,pforest->topo->conn,coords));
38690a96aa3bSJed Brown       }
38700a96aa3bSJed Brown     }
38710a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
38720a96aa3bSJed Brown       p4est_tree_t     *tree    = &(trees[t]);
38730a96aa3bSJed Brown       PetscInt         offset   = cLocalStart + tree->quadrants_offset, i;
38740a96aa3bSJed Brown       PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
38750a96aa3bSJed Brown       p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
38760a96aa3bSJed Brown 
38770a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
38780a96aa3bSJed Brown         PetscInt count = i + offset;
38790a96aa3bSJed Brown 
38809566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count,&quads[i],t,pforest->topo->conn,coords));
38810a96aa3bSJed Brown       }
38820a96aa3bSJed Brown     }
38830a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
38840a96aa3bSJed Brown       p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38850a96aa3bSJed Brown       PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
38860a96aa3bSJed Brown       PetscInt         count;
38870a96aa3bSJed Brown 
38880a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
38890a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
38900a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
38910a96aa3bSJed Brown 
38929566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count + cLocalEnd,quad,t,pforest->topo->conn,coords));
38930a96aa3bSJed Brown       }
38940a96aa3bSJed Brown     }
38950a96aa3bSJed Brown   }
38969566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordLocalVec,&coords));
38970a96aa3bSJed Brown   PetscFunctionReturn(0);
38980a96aa3bSJed Brown }
38990a96aa3bSJed Brown 
39000a96aa3bSJed Brown static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
39010a96aa3bSJed Brown {
39020a96aa3bSJed Brown   DM_Forest         *forest;
39030a96aa3bSJed Brown   DM_Forest_pforest *pforest;
39040a96aa3bSJed Brown   DM                base;
39050a96aa3bSJed Brown   Vec               coordinates, cVec;
39060a96aa3bSJed Brown   PetscSection      oldSection, baseSection = NULL, newSection;
39070a96aa3bSJed Brown   const PetscScalar *coords;
39080a96aa3bSJed Brown   PetscScalar       *coords2;
39090a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, coarsePoint;
39100a96aa3bSJed Brown   PetscInt          cDim, newStart, newEnd, dof, cdof = -1;
39110a96aa3bSJed Brown   PetscInt          v, vStart, vEnd, cp, cStart, cEnd, cEndInterior, *coarsePoints;
39120a96aa3bSJed Brown   PetscInt          *localize, overlap;
39130a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
39140a96aa3bSJed Brown   p4est_tree_t      *trees;
39150a96aa3bSJed Brown   PetscBool         isper, baseLocalized = PETSC_FALSE;
39160a96aa3bSJed Brown 
39170a96aa3bSJed Brown   PetscFunctionBegin;
39189566063dSJacob Faibussowitsch   PetscCall(DMGetPeriodicity(dm,&isper,NULL,NULL,NULL));
39190a96aa3bSJed Brown   if (!isper) PetscFunctionReturn(0);
39200a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
39219566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cDim));
39220a96aa3bSJed Brown   cdof = P4EST_CHILDREN*cDim;
39239566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
39240a96aa3bSJed Brown   if (base) {
39259566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocalized(base,&baseLocalized));
39260a96aa3bSJed Brown   }
39270a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
39289566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &newStart, &newEnd));
39290a96aa3bSJed Brown 
39309566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
39319566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(overlap ? newEnd - newStart : 0,&localize));
39320a96aa3bSJed Brown 
39339566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &newSection));
39349566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(newSection, 1));
39359566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim));
39369566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSection, newStart, newEnd));
39370a96aa3bSJed Brown 
39389566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &oldSection));
39399566063dSJacob Faibussowitsch   if (base) PetscCall(DMGetCoordinateSection(base, &baseSection));
39409566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex,0,&vStart,&vEnd));
39410a96aa3bSJed Brown   for (v = vStart; v < vEnd; ++v) {
39429566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(oldSection, v, &dof));
39439566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(newSection, v, dof));
39449566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(newSection, v, 0, dof));
39450a96aa3bSJed Brown     if (overlap) localize[v] = dof;
39460a96aa3bSJed Brown   }
39470a96aa3bSJed Brown 
39480a96aa3bSJed Brown   forest      = (DM_Forest*) dm->data;
39490a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
39500a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
39510a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
39520a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
39530a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
39540a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
39550a96aa3bSJed Brown 
39560a96aa3bSJed Brown   cp = 0;
39579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
39589566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
39590a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
39609566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cEnd-cStart,&coarsePoints));
39610a96aa3bSJed Brown   if (cLocalStart > 0) {
39620a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
39630a96aa3bSJed Brown     PetscInt         count;
39640a96aa3bSJed Brown 
39650a96aa3bSJed Brown     for (count = 0; count < cLocalStart; count++) {
39660a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count];
39670a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
39680a96aa3bSJed Brown 
39699566063dSJacob Faibussowitsch       if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
39709566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(newSection, count, cdof));
39719566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(newSection, count, 0, cdof));
39720a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
39730a96aa3bSJed Brown       if (overlap) localize[count] = cdof;
39740a96aa3bSJed Brown     }
39750a96aa3bSJed Brown   }
39760a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
39770a96aa3bSJed Brown     p4est_tree_t *tree    = &(trees[t]);
39780a96aa3bSJed Brown     PetscInt     offset   = cLocalStart + tree->quadrants_offset;
39790a96aa3bSJed Brown     PetscInt     numQuads = (PetscInt) tree->quadrants.elem_count;
39800a96aa3bSJed Brown     PetscInt     i;
39810a96aa3bSJed Brown 
39820a96aa3bSJed Brown     if (!numQuads) continue;
39830a96aa3bSJed Brown     coarsePoint = t;
39849566063dSJacob Faibussowitsch     if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
39850a96aa3bSJed Brown     for (i = 0; i < numQuads; i++) {
39860a96aa3bSJed Brown       PetscInt newCell = i + offset;
39870a96aa3bSJed Brown 
39889566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(newSection, newCell, cdof));
39899566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
39900a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
39910a96aa3bSJed Brown       if (overlap) localize[newCell] = cdof;
39920a96aa3bSJed Brown     }
39930a96aa3bSJed Brown   }
39940a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
39950a96aa3bSJed Brown     p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
39960a96aa3bSJed Brown     PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
39970a96aa3bSJed Brown     PetscInt         count;
39980a96aa3bSJed Brown 
39990a96aa3bSJed Brown     for (count = 0; count < numGhosts - cLocalStart; count++) {
40000a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
40010a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
40020a96aa3bSJed Brown       PetscInt newCell = count + cLocalEnd;
40030a96aa3bSJed Brown 
40049566063dSJacob Faibussowitsch       if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
40059566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(newSection, newCell, cdof));
40069566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
40070a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
40080a96aa3bSJed Brown       if (overlap) localize[newCell] = cdof;
40090a96aa3bSJed Brown     }
40100a96aa3bSJed Brown   }
40111dca8a05SBarry Smith   PetscCheck(cp == cEnd - cStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT,cp,cEnd-cStart);
40120a96aa3bSJed Brown 
40130a96aa3bSJed Brown   if (base) { /* we need to localize on all the cells in the star of the coarse cell vertices */
40140a96aa3bSJed Brown     PetscInt *closure = NULL, closureSize;
40150a96aa3bSJed Brown     PetscInt p, i, c, vStartBase, vEndBase, cStartBase, cEndBase;
40160a96aa3bSJed Brown 
40179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(base,0,&cStartBase,&cEndBase));
40189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase));
40190a96aa3bSJed Brown     for (p = cStart; p < cEnd; p++) {
40200a96aa3bSJed Brown       coarsePoint = coarsePoints[p-cStart];
40210a96aa3bSJed Brown       if (coarsePoint < 0) continue;
40229566063dSJacob Faibussowitsch       if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
40239566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure));
40240a96aa3bSJed Brown       for (c = 0; c < closureSize; c++) {
40250a96aa3bSJed Brown         PetscInt *star = NULL, starSize;
40260a96aa3bSJed Brown         PetscInt j, v = closure[2 * c];
40270a96aa3bSJed Brown 
40280a96aa3bSJed Brown         if (v < vStartBase || v > vEndBase) continue;
40299566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star));
40300a96aa3bSJed Brown         for (j = 0; j < starSize; j++) {
40310a96aa3bSJed Brown           PetscInt cell = star[2 * j];
40320a96aa3bSJed Brown 
40330a96aa3bSJed Brown           if (cStartBase <= cell && cell < cEndBase) {
40340a96aa3bSJed Brown             p4est_tree_t *tree;
40350a96aa3bSJed Brown             PetscInt     offset,numQuads;
40360a96aa3bSJed Brown 
40370a96aa3bSJed Brown             if (cell < flt || cell > llt) continue;
40380a96aa3bSJed Brown             tree     = &(trees[cell]);
40390a96aa3bSJed Brown             offset   = cLocalStart + tree->quadrants_offset;
40400a96aa3bSJed Brown             numQuads = (PetscInt) tree->quadrants.elem_count;
40410a96aa3bSJed Brown             for (i = 0; i < numQuads; i++) {
40420a96aa3bSJed Brown               PetscInt newCell = i + offset;
40430a96aa3bSJed Brown 
40449566063dSJacob Faibussowitsch               PetscCall(PetscSectionSetDof(newSection, newCell, cdof));
40459566063dSJacob Faibussowitsch               PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
40460a96aa3bSJed Brown               if (overlap) localize[newCell] = cdof;
40470a96aa3bSJed Brown             }
40480a96aa3bSJed Brown           }
40490a96aa3bSJed Brown         }
40509566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star));
40510a96aa3bSJed Brown       }
40529566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure));
40530a96aa3bSJed Brown     }
40540a96aa3bSJed Brown   }
40559566063dSJacob Faibussowitsch   PetscCall(PetscFree(coarsePoints));
40560a96aa3bSJed Brown 
40570a96aa3bSJed Brown   /* final consensus with overlap */
40580a96aa3bSJed Brown   if (overlap) {
40590a96aa3bSJed Brown     PetscSF  sf;
40600a96aa3bSJed Brown     PetscInt *localizeGlobal;
40610a96aa3bSJed Brown 
40629566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex,&sf));
40639566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newEnd-newStart,&localizeGlobal));
40640a96aa3bSJed Brown     for (v = newStart; v < newEnd; v++) localizeGlobal[v - newStart] = localize[v - newStart];
40659566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE));
40669566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE));
40670a96aa3bSJed Brown     for (v = newStart; v < newEnd; v++) {
40689566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(newSection, v, localizeGlobal[v-newStart]));
40699566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(newSection, v, 0, localizeGlobal[v-newStart]));
40700a96aa3bSJed Brown     }
40719566063dSJacob Faibussowitsch     PetscCall(PetscFree(localizeGlobal));
40720a96aa3bSJed Brown   }
40739566063dSJacob Faibussowitsch   PetscCall(PetscFree(localize));
40749566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSection));
40759566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)oldSection));
40769566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateSection(plex, cDim, newSection));
40779566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &v));
40789566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
40799566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)cVec,"coordinates"));
40809566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(cVec, cDim));
40819566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE));
40829566063dSJacob Faibussowitsch   PetscCall(VecSetType(cVec, VECSTANDARD));
40839566063dSJacob Faibussowitsch   PetscCall(VecSet(cVec, PETSC_MIN_REAL));
40840a96aa3bSJed Brown 
40850a96aa3bSJed Brown   /* Copy over vertex coordinates */
40869566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex, &coordinates));
408728b400f6SJacob Faibussowitsch   PetscCheck(coordinates,PetscObjectComm((PetscObject)plex),PETSC_ERR_SUP,"Missing local coordinates vector");
40889566063dSJacob Faibussowitsch   PetscCall(VecGetArray(cVec, &coords2));
40899566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
40900a96aa3bSJed Brown   for (v = vStart; v < vEnd; ++v) {
40910a96aa3bSJed Brown     PetscInt d, off,off2;
40920a96aa3bSJed Brown 
40939566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(oldSection, v, &dof));
40949566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(oldSection, v, &off));
40959566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(newSection, v, &off2));
40960a96aa3bSJed Brown     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
40970a96aa3bSJed Brown   }
40989566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
40990a96aa3bSJed Brown 
41000a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
41010a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
41020a96aa3bSJed Brown     p4est_tree_t     *tree    = &(trees[t]);
41030a96aa3bSJed Brown     const double     *v       = pforest->topo->conn->vertices;
41040a96aa3bSJed Brown     p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
41050a96aa3bSJed Brown     PetscInt         offset   = cLocalStart + tree->quadrants_offset;
41060a96aa3bSJed Brown     PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
41070a96aa3bSJed Brown     p4est_topidx_t   vt[8]    = {0,0,0,0,0,0,0,0};
41080a96aa3bSJed Brown     PetscInt         i,k;
41090a96aa3bSJed Brown 
41100a96aa3bSJed Brown     if (!numQuads) continue;
41110a96aa3bSJed Brown     for (k = 0; k < P4EST_CHILDREN; ++k) {
41120a96aa3bSJed Brown       vt[k] = pforest->topo->conn->tree_to_vertex[t * P4EST_CHILDREN + k];
41130a96aa3bSJed Brown     }
41140a96aa3bSJed Brown 
41150a96aa3bSJed Brown     for (i = 0; i < numQuads; i++) {
41160a96aa3bSJed Brown       p4est_quadrant_t  *quad = &quads[i];
41170a96aa3bSJed Brown       const PetscReal   intsize = 1.0 / P4EST_ROOT_LEN;
41180a96aa3bSJed Brown       PetscReal         h2;
41190a96aa3bSJed Brown       PetscScalar       xyz[3];
41200a96aa3bSJed Brown #ifdef P4_TO_P8
41210a96aa3bSJed Brown       PetscInt          zi;
41220a96aa3bSJed Brown #endif
41230a96aa3bSJed Brown       PetscInt          yi,xi;
41240a96aa3bSJed Brown       PetscInt          off2;
41250a96aa3bSJed Brown       PetscInt          newCell = i + offset;
41260a96aa3bSJed Brown 
41279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(newSection, newCell, 0, &cdof));
41280a96aa3bSJed Brown       if (!cdof) continue;
41290a96aa3bSJed Brown 
41300a96aa3bSJed Brown       h2   = .5 * intsize * P4EST_QUADRANT_LEN (quad->level);
41310a96aa3bSJed Brown       k    = 0;
41329566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSection, newCell, &off2));
41330a96aa3bSJed Brown #ifdef P4_TO_P8
41340a96aa3bSJed Brown       for (zi = 0; zi < 2; ++zi) {
41350a96aa3bSJed Brown         const PetscReal eta_z = intsize * quad->z + h2 * (1. + (zi * 2 - 1));
41360a96aa3bSJed Brown #else
41370a96aa3bSJed Brown       {
41380a96aa3bSJed Brown         const PetscReal eta_z = 0.0;
41390a96aa3bSJed Brown #endif
41400a96aa3bSJed Brown         for (yi = 0; yi < 2; ++yi) {
41410a96aa3bSJed Brown           const PetscReal eta_y = intsize * quad->y + h2 * (1. + (yi * 2 - 1));
41420a96aa3bSJed Brown           for (xi = 0; xi < 2; ++xi) {
41430a96aa3bSJed Brown             const PetscReal eta_x = intsize * quad->x + h2 * (1. + (xi * 2 - 1));
41440a96aa3bSJed Brown             PetscInt    j;
41450a96aa3bSJed Brown 
41460a96aa3bSJed Brown             for (j = 0; j < 3; ++j) {
41470a96aa3bSJed Brown               xyz[j] = ((1. - eta_z) * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[0] + j] +
41480a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[1] + j]) +
41490a96aa3bSJed Brown                                               eta_y  * ((1. - eta_x) * v[3 * vt[2] + j] +
41500a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[3] + j]))
41510a96aa3bSJed Brown                         +     eta_z  * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[4] + j] +
41520a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[5] + j]) +
41530a96aa3bSJed Brown                                               eta_y  * ((1. - eta_x) * v[3 * vt[6] + j] +
41540a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[7] + j])));
41550a96aa3bSJed Brown             }
41560a96aa3bSJed Brown             for (j = 0; j < cDim; ++j) coords2[off2 + cDim*P4estVertToPetscVert[k] + j] = xyz[j];
41570a96aa3bSJed Brown             ++k;
41580a96aa3bSJed Brown           }
41590a96aa3bSJed Brown         }
41600a96aa3bSJed Brown       }
41610a96aa3bSJed Brown     }
41620a96aa3bSJed Brown   }
41639566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cVec, &coords2));
41649566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(plex, cVec));
41659566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cVec));
41669566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&newSection));
41679566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&oldSection));
41680a96aa3bSJed Brown   PetscFunctionReturn(0);
41690a96aa3bSJed Brown }
41700a96aa3bSJed Brown 
41710a96aa3bSJed Brown #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
41720a96aa3bSJed Brown static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
41730a96aa3bSJed Brown {
41740a96aa3bSJed Brown   DM_Forest         *forest;
41750a96aa3bSJed Brown   DM_Forest_pforest *pforest;
41760a96aa3bSJed Brown 
41770a96aa3bSJed Brown   PetscFunctionBegin;
41780a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
41790a96aa3bSJed Brown   pforest = (DM_Forest_pforest *) forest->data;
41809566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointAdaptToSelfSF)));
41819566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointSelfToAdaptSF)));
41829566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
41839566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
41840a96aa3bSJed Brown   PetscFunctionReturn(0);
41850a96aa3bSJed Brown }
41860a96aa3bSJed Brown 
41870a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
41880a96aa3bSJed Brown {
41890a96aa3bSJed Brown   DM_Forest            *forest;
41900a96aa3bSJed Brown   DM_Forest_pforest    *pforest;
41910a96aa3bSJed Brown   DM                   refTree, newPlex, base;
41920a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
41930a96aa3bSJed Brown   MPI_Comm             comm;
41940a96aa3bSJed Brown   PetscBool            isPforest;
41950a96aa3bSJed Brown   PetscInt             dim;
41960a96aa3bSJed Brown   PetscInt             overlap;
41970a96aa3bSJed Brown   p4est_connect_type_t ctype;
41980a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
41990a96aa3bSJed Brown   sc_array_t           *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
42000a96aa3bSJed Brown   PetscSection         parentSection;
42010a96aa3bSJed Brown   PetscSF              pointSF;
42020a96aa3bSJed Brown   size_t               zz, count;
42030a96aa3bSJed Brown   PetscInt             pStart, pEnd;
42040a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
42050a96aa3bSJed Brown 
42060a96aa3bSJed Brown   PetscFunctionBegin;
42070a96aa3bSJed Brown 
42080a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
42090a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
42109566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPFOREST,&isPforest));
421128b400f6SJacob Faibussowitsch   PetscCheck(isPforest,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPFOREST,((PetscObject)dm)->type_name);
42129566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dim));
421363a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim);
42140a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
42150a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
42169566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
42170a96aa3bSJed Brown   if (base) {
42189566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(base,"ghost",&ghostLabelBase));
42190a96aa3bSJed Brown   }
42200a96aa3bSJed Brown   if (!pforest->plex) {
42210a96aa3bSJed Brown     PetscMPIInt size;
42220a96aa3bSJed Brown 
42239566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm,&size));
42249566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm,&newPlex));
42259566063dSJacob Faibussowitsch     PetscCall(DMSetType(newPlex,DMPLEX));
42269566063dSJacob Faibussowitsch     PetscCall(DMSetMatType(newPlex,dm->mattype));
42270a96aa3bSJed Brown     /* share labels */
42289566063dSJacob Faibussowitsch     PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
42299566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyDimension(dm,&adjDim));
42309566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyCodimension(dm,&adjCodim));
42319566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm,&coordDim));
42320a96aa3bSJed Brown     if (adjDim == 0) {
42330a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
42340a96aa3bSJed Brown     } else if (adjCodim == 1) {
42350a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
42360a96aa3bSJed Brown #if defined(P4_TO_P8)
42370a96aa3bSJed Brown     } else if (adjDim == 1) {
42380a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
42390a96aa3bSJed Brown #endif
42400a96aa3bSJed Brown     } else {
424163a3b9bcSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Invalid adjacency dimension %" PetscInt_FMT,adjDim);
42420a96aa3bSJed Brown     }
424363a3b9bcSJacob 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);
42449566063dSJacob Faibussowitsch     PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
424560667520SVaclav Hapla     PetscCall(DMPlexSetOverlap_Plex(newPlex,NULL,overlap));
42460a96aa3bSJed Brown 
42470a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
42480a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
42490a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
42500a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
42510a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
42520a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
42530a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
42540a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
42550a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
42560a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
42570a96aa3bSJed Brown 
42580a96aa3bSJed Brown     PetscStackCallP4est(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));
42590a96aa3bSJed Brown 
42600a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt) first_local_quad;
42610a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt) pforest->forest->local_num_quadrants;
42629566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
42639566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
42649566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
42659566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
42669566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, coordDim));
42679566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(children));
42689566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(parents));
42699566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(childids));
42709566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(leaves));
42719566063dSJacob Faibussowitsch     PetscCall(locidx_pair_to_PetscSFNode(remotes));
42720a96aa3bSJed Brown 
42739566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(newPlex,P4EST_DIM));
42749566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDim(newPlex,coordDim));
42759566063dSJacob Faibussowitsch     PetscCall(DMPlexSetMaxProjectionHeight(newPlex,P4EST_DIM - 1));
42769566063dSJacob 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));
42779566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(newPlex));
42789566063dSJacob Faibussowitsch     PetscCall(DMCreateReferenceTree_pforest(comm,&refTree));
42799566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(newPlex,refTree));
42809566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(comm,&parentSection));
42819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(newPlex,&pStart,&pEnd));
42829566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection,pStart,pEnd));
42830a96aa3bSJed Brown     count = children->elem_count;
42840a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
42850a96aa3bSJed Brown       PetscInt child = *((PetscInt*) sc_array_index(children,zz));
42860a96aa3bSJed Brown 
42879566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(parentSection,child,1));
42880a96aa3bSJed Brown     }
42899566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
42909566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(newPlex,parentSection,(PetscInt*)parents->array,(PetscInt*)childids->array));
42919566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&parentSection));
42929566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm,&pointSF));
42930a96aa3bSJed Brown     /*
42940a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
42950a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
42960a96aa3bSJed Brown     */
42979566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(pointSF,pEnd - pStart,(PetscInt)leaves->elem_count,(PetscInt*)leaves->array,PETSC_COPY_VALUES,(PetscSFNode*)remotes->array,PETSC_COPY_VALUES));
42989566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(newPlex,pointSF));
42999566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(dm,pointSF));
43000a96aa3bSJed Brown     {
43010a96aa3bSJed Brown       DM coordDM;
43020a96aa3bSJed Brown 
43039566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43049566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(coordDM,pointSF));
43050a96aa3bSJed Brown     }
43069566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointSF));
43070a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
43080a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
43090a96aa3bSJed Brown     sc_array_destroy (cones);
43100a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
43110a96aa3bSJed Brown     sc_array_destroy (coords);
43120a96aa3bSJed Brown     sc_array_destroy (children);
43130a96aa3bSJed Brown     sc_array_destroy (parents);
43140a96aa3bSJed Brown     sc_array_destroy (childids);
43150a96aa3bSJed Brown     sc_array_destroy (leaves);
43160a96aa3bSJed Brown     sc_array_destroy (remotes);
43170a96aa3bSJed Brown 
43180a96aa3bSJed Brown     {
43190a96aa3bSJed Brown       PetscBool             isper;
43200a96aa3bSJed Brown       const PetscReal      *maxCell, *L;
43210a96aa3bSJed Brown       const DMBoundaryType *bd;
43220a96aa3bSJed Brown 
43239566063dSJacob Faibussowitsch       PetscCall(DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd));
43249566063dSJacob Faibussowitsch       PetscCall(DMSetPeriodicity(newPlex,isper,maxCell,L,bd));
43259566063dSJacob Faibussowitsch       PetscCall(DMPforestLocalizeCoordinates(dm,newPlex));
43260a96aa3bSJed Brown     }
43270a96aa3bSJed Brown 
43280a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
43290a96aa3bSJed Brown       Vec               coordsGlobal, coordsLocal;
43300a96aa3bSJed Brown       const PetscScalar *globalArray;
43310a96aa3bSJed Brown       PetscScalar       *localArray;
43320a96aa3bSJed Brown       PetscSF           coordSF;
43330a96aa3bSJed Brown       DM                coordDM;
43340a96aa3bSJed Brown 
43359566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43369566063dSJacob Faibussowitsch       PetscCall(DMGetSectionSF(coordDM,&coordSF));
43379566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinates(newPlex, &coordsGlobal));
43389566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal));
43399566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordsGlobal, &globalArray));
43409566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordsLocal, &localArray));
43419566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
43429566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
43439566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordsLocal, &localArray));
43449566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray));
43459566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal));
43460a96aa3bSJed Brown     }
43479566063dSJacob Faibussowitsch     PetscCall(DMPforestMapCoordinates(dm,newPlex));
43480a96aa3bSJed Brown 
43490a96aa3bSJed Brown     pforest->plex = newPlex;
43500a96aa3bSJed Brown 
43510a96aa3bSJed Brown     /* copy labels */
43529566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsFinalize(dm,newPlex));
43530a96aa3bSJed Brown 
43540a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
43550a96aa3bSJed Brown       PetscInt numAdded;
43560a96aa3bSJed Brown       DM       newPlexGhosted;
43570a96aa3bSJed Brown       void     *ctx;
43580a96aa3bSJed Brown 
43599566063dSJacob Faibussowitsch       PetscCall(DMPlexConstructGhostCells(newPlex,pforest->ghostName,&numAdded,&newPlexGhosted));
43609566063dSJacob Faibussowitsch       PetscCall(DMGetApplicationContext(newPlex,&ctx));
43619566063dSJacob Faibussowitsch       PetscCall(DMSetApplicationContext(newPlexGhosted,ctx));
43620a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
43639566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(newPlexGhosted,&pointSF));
43649566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(dm,pointSF));
43659566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&newPlex));
43669566063dSJacob Faibussowitsch       PetscCall(DMPlexSetReferenceTree(newPlexGhosted,refTree));
43679566063dSJacob Faibussowitsch       PetscCall(DMForestClearAdaptivityForest_pforest(dm));
43680a96aa3bSJed Brown       newPlex = newPlexGhosted;
43690a96aa3bSJed Brown 
43700a96aa3bSJed Brown       /* share the labels back */
43719566063dSJacob Faibussowitsch       PetscCall(DMDestroyLabelLinkList_Internal(dm));
43729566063dSJacob Faibussowitsch       PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
43730a96aa3bSJed Brown       pforest->plex = newPlex;
43740a96aa3bSJed Brown     }
43759566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&refTree));
43760a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
43775f80ce2aSJacob Faibussowitsch 
4378d0609cedSBarry Smith       PetscObjectOptionsBegin((PetscObject)newPlex);
43799566063dSJacob Faibussowitsch       PetscCall(DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject,newPlex));
43809566063dSJacob Faibussowitsch       PetscCall(PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)newPlex));
4381d0609cedSBarry Smith       PetscOptionsEnd();
43820a96aa3bSJed Brown     }
43839566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(newPlex,NULL,"-dm_p4est_plex_view"));
43840a96aa3bSJed Brown     {
43850a96aa3bSJed Brown       PetscSection coordsSec;
43860a96aa3bSJed Brown       Vec          coords;
43870a96aa3bSJed Brown       PetscInt     cDim;
43880a96aa3bSJed Brown 
43899566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(newPlex,&cDim));
43909566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(newPlex,&coordsSec));
43919566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinateSection(dm,cDim,coordsSec));
43929566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex,&coords));
43939566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(dm,coords));
43940a96aa3bSJed Brown     }
43950a96aa3bSJed Brown   }
43960a96aa3bSJed Brown   newPlex = pforest->plex;
43970a96aa3bSJed Brown   if (plex) {
43980a96aa3bSJed Brown     DM coordDM;
43990a96aa3bSJed Brown 
44009566063dSJacob Faibussowitsch     PetscCall(DMClone(newPlex,plex));
44019566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
44029566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDM(*plex,coordDM));
44039566063dSJacob Faibussowitsch     PetscCall(DMShareDiscretization(dm,*plex));
44040a96aa3bSJed Brown   }
44050a96aa3bSJed Brown   PetscFunctionReturn(0);
44060a96aa3bSJed Brown }
44070a96aa3bSJed Brown 
44080a96aa3bSJed Brown static PetscErrorCode DMSetFromOptions_pforest(PetscOptionItems *PetscOptionsObject,DM dm)
44090a96aa3bSJed Brown {
44100a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44110a96aa3bSJed Brown   char              stringBuffer[256];
44120a96aa3bSJed Brown   PetscBool         flg;
44130a96aa3bSJed Brown 
44140a96aa3bSJed Brown   PetscFunctionBegin;
44159566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions_Forest(PetscOptionsObject,dm));
4416d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"DM" P4EST_STRING " options");
44179566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening","partition forest to allow for coarsening","DMP4estSetPartitionForCoarsening",pforest->partition_for_coarsening,&(pforest->partition_for_coarsening),NULL));
44189566063dSJacob 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));
4419d0609cedSBarry Smith   PetscOptionsHeadEnd();
44200a96aa3bSJed Brown   if (flg) {
44219566063dSJacob Faibussowitsch     PetscCall(PetscFree(pforest->ghostName));
44229566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(stringBuffer,&pforest->ghostName));
44230a96aa3bSJed Brown   }
44240a96aa3bSJed Brown   PetscFunctionReturn(0);
44250a96aa3bSJed Brown }
44260a96aa3bSJed Brown 
44270a96aa3bSJed Brown #if !defined(P4_TO_P8)
44280a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
44290a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
44300a96aa3bSJed Brown #else
44310a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
44320a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
44330a96aa3bSJed Brown #endif
44340a96aa3bSJed Brown 
44350a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
44360a96aa3bSJed Brown {
44370a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44380a96aa3bSJed Brown 
44390a96aa3bSJed Brown   PetscFunctionBegin;
44400a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
44410a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44420a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
44430a96aa3bSJed Brown   PetscFunctionReturn(0);
44440a96aa3bSJed Brown }
44450a96aa3bSJed Brown 
44460a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
44470a96aa3bSJed Brown {
44480a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44490a96aa3bSJed Brown 
44500a96aa3bSJed Brown   PetscFunctionBegin;
44510a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
44520a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44530a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
44540a96aa3bSJed Brown   PetscFunctionReturn(0);
44550a96aa3bSJed Brown }
44560a96aa3bSJed Brown 
44570a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM dm,DM *plex)
44580a96aa3bSJed Brown {
44590a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44600a96aa3bSJed Brown 
44610a96aa3bSJed Brown   PetscFunctionBegin;
44620a96aa3bSJed Brown   if (plex) *plex = NULL;
44639566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
44640a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44650a96aa3bSJed Brown   if (!pforest->plex) {
44669566063dSJacob Faibussowitsch     PetscCall(DMConvert_pforest_plex(dm,DMPLEX,NULL));
44670a96aa3bSJed Brown   }
44689566063dSJacob Faibussowitsch   PetscCall(DMShareDiscretization(dm,pforest->plex));
44690a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
44700a96aa3bSJed Brown   PetscFunctionReturn(0);
44710a96aa3bSJed Brown }
44720a96aa3bSJed Brown 
44730a96aa3bSJed Brown #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
44740a96aa3bSJed Brown static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
44750a96aa3bSJed Brown {
44760a96aa3bSJed Brown   PetscSection   gsc, gsf;
44770a96aa3bSJed Brown   PetscInt       m, n;
44780a96aa3bSJed Brown   DM             cdm;
44790a96aa3bSJed Brown 
44800a96aa3bSJed Brown   PetscFunctionBegin;
44819566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
44829566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
44839566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
44849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
44850a96aa3bSJed Brown 
44869566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), interpolation));
44879566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
44889566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, MATAIJ));
44890a96aa3bSJed Brown 
44909566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
449108401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only interpolation from coarse DM for now");
44920a96aa3bSJed Brown 
44930a96aa3bSJed Brown   {
44940a96aa3bSJed Brown     DM       plexF, plexC;
44950a96aa3bSJed Brown     PetscSF  sf;
44960a96aa3bSJed Brown     PetscInt *cids;
44970a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
44980a96aa3bSJed Brown 
44999566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse,&plexC));
45009566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine,&plexF));
45019566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
45029566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
45039566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
45049566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
45059566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
45060a96aa3bSJed Brown   }
45079566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
45080a96aa3bSJed Brown   /* Use naive scaling */
45099566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
45100a96aa3bSJed Brown   PetscFunctionReturn(0);
45110a96aa3bSJed Brown }
45120a96aa3bSJed Brown 
45130a96aa3bSJed Brown #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
45140a96aa3bSJed Brown static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
45150a96aa3bSJed Brown {
45160a96aa3bSJed Brown   PetscSection   gsc, gsf;
45170a96aa3bSJed Brown   PetscInt       m, n;
45180a96aa3bSJed Brown   DM             cdm;
45190a96aa3bSJed Brown 
45200a96aa3bSJed Brown   PetscFunctionBegin;
45219566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
45229566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n));
45239566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
45249566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m));
45250a96aa3bSJed Brown 
45269566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), injection));
45279566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
45289566063dSJacob Faibussowitsch   PetscCall(MatSetType(*injection, MATAIJ));
45290a96aa3bSJed Brown 
45309566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
453108401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only injection to coarse DM for now");
45320a96aa3bSJed Brown 
45330a96aa3bSJed Brown   {
45340a96aa3bSJed Brown     DM       plexF, plexC;
45350a96aa3bSJed Brown     PetscSF  sf;
45360a96aa3bSJed Brown     PetscInt *cids;
45370a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
45380a96aa3bSJed Brown 
45399566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse,&plexC));
45409566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine,&plexF));
45419566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
45429566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
45439566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
45449566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
45459566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
45460a96aa3bSJed Brown   }
45479566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
45480a96aa3bSJed Brown   /* Use naive scaling */
45490a96aa3bSJed Brown   PetscFunctionReturn(0);
45500a96aa3bSJed Brown }
45510a96aa3bSJed Brown 
45520a96aa3bSJed Brown #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
45530a96aa3bSJed Brown static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
45540a96aa3bSJed Brown {
45550a96aa3bSJed Brown   DM             dmIn, dmVecIn, base, basec, plex, coarseDM;
45560a96aa3bSJed Brown   DM             *hierarchy;
45570a96aa3bSJed Brown   PetscSF        sfRed = NULL;
45580a96aa3bSJed Brown   PetscDS        ds;
45590a96aa3bSJed Brown   Vec            vecInLocal, vecOutLocal;
45600a96aa3bSJed Brown   DMLabel        subpointMap;
45610a96aa3bSJed Brown   PetscInt       minLevel, mh, n_hi, i;
45620a96aa3bSJed Brown   PetscBool      hiforest, *hierarchy_forest;
45630a96aa3bSJed Brown 
45640a96aa3bSJed Brown   PetscFunctionBegin;
45659566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vecIn,&dmVecIn));
45669566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmVecIn,&ds));
456728b400f6SJacob Faibussowitsch   PetscCheck(ds,PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Cannot transfer without a PetscDS object");
45680a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
45690a96aa3bSJed Brown     PetscSection section;
45700a96aa3bSJed Brown     PetscInt     Nf;
45710a96aa3bSJed Brown 
45729566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn,&section));
45739566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section,&Nf));
457463a3b9bcSJacob 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);
45750a96aa3bSJed Brown   }
45769566063dSJacob Faibussowitsch   PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
457763a3b9bcSJacob Faibussowitsch   PetscCheck(!minLevel,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)",minLevel);
45789566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
457928b400f6SJacob Faibussowitsch   PetscCheck(base,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing base DM");
45800a96aa3bSJed Brown 
45819566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut,0.0));
45820a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
45839566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45840a96aa3bSJed Brown   } else {
45850a96aa3bSJed Brown     PetscSection secIn, secInRed;
45860a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
45870a96aa3bSJed Brown 
45889566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)base,"_base_migration_sf",(PetscObject*)&sfRed));
458928b400f6SJacob Faibussowitsch     PetscCheck(sfRed,PETSC_COMM_SELF,PETSC_ERR_SUP,"Not the DM set with DMForestSetBaseDM()");
45909566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn),&secInRed));
45919566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF,&vecInRed));
45929566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn,&secIn));
45939566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmVecIn,&vecInLocal));
45949566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
45959566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
45969566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeField(dmVecIn,sfRed,secIn,vecInLocal,secInRed,vecInRed));
45979566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmVecIn,&vecInLocal));
45989566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secInRed));
45990a96aa3bSJed Brown     vecIn = vecInRed;
46000a96aa3bSJed Brown   }
46010a96aa3bSJed Brown 
46020a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
46030a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
46040a96aa3bSJed Brown   hiforest = PETSC_TRUE;
46050a96aa3bSJed Brown 
46060a96aa3bSJed Brown   /* upsweep to the coarsest DM */
46070a96aa3bSJed Brown   n_hi = 0;
46080a96aa3bSJed Brown   coarseDM = dm;
46090a96aa3bSJed Brown   do {
46100a96aa3bSJed Brown     PetscBool isforest;
46110a96aa3bSJed Brown 
46120a96aa3bSJed Brown     dmIn = coarseDM;
46130a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
46149566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dmIn));
46159566063dSJacob Faibussowitsch     PetscCall(DMIsForest(dmIn,&isforest));
461628b400f6SJacob Faibussowitsch     PetscCheck(isforest,PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Cannot currently transfer through a mixed hierarchy! Found DM type %s",((PetscObject)dmIn)->type_name);
46170a96aa3bSJed Brown     coarseDM = NULL;
46180a96aa3bSJed Brown     if (hiforest) {
46199566063dSJacob Faibussowitsch       PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM));
46200a96aa3bSJed Brown     }
46210a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
46220a96aa3bSJed Brown       hiforest = PETSC_FALSE;
46239566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn,&coarseDM));
46240a96aa3bSJed Brown     }
46250a96aa3bSJed Brown     n_hi++;
46260a96aa3bSJed Brown   } while (coarseDM);
46270a96aa3bSJed Brown 
46289566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n_hi,&hierarchy,n_hi,&hierarchy_forest));
46290a96aa3bSJed Brown 
46300a96aa3bSJed Brown   i = 0;
46310a96aa3bSJed Brown   hiforest = PETSC_TRUE;
46320a96aa3bSJed Brown   coarseDM = dm;
46330a96aa3bSJed Brown   do {
46340a96aa3bSJed Brown     dmIn = coarseDM;
46350a96aa3bSJed Brown     coarseDM = NULL;
46360a96aa3bSJed Brown     if (hiforest) {
46379566063dSJacob Faibussowitsch       PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM));
46380a96aa3bSJed Brown     }
46390a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
46400a96aa3bSJed Brown       hiforest = PETSC_FALSE;
46419566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn,&coarseDM));
46420a96aa3bSJed Brown     }
46430a96aa3bSJed Brown     i++;
46440a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
46450a96aa3bSJed Brown   } while (coarseDM);
46460a96aa3bSJed Brown 
46470a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
46489566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn,&plex));
46490a96aa3bSJed Brown 
46500a96aa3bSJed Brown   /* Check this plex is compatible with the base */
46510a96aa3bSJed Brown   {
46520a96aa3bSJed Brown     IS       gnum[2];
46530a96aa3bSJed Brown     PetscInt ncells[2],gncells[2];
46540a96aa3bSJed Brown 
46559566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(base,&gnum[0]));
46569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(plex,&gnum[1]));
46579566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[0],NULL,&ncells[0]));
46589566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[1],NULL,&ncells[1]));
46591c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(ncells,gncells,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
466063a3b9bcSJacob 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);
46610a96aa3bSJed Brown   }
46620a96aa3bSJed Brown 
46639566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dmIn,"_forest_base_subpoint_map",&subpointMap));
466428b400f6SJacob Faibussowitsch   PetscCheck(subpointMap,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing _forest_base_subpoint_map label");
46650a96aa3bSJed Brown 
46669566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(base,&mh));
46679566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(plex,mh));
46680a96aa3bSJed Brown 
46699566063dSJacob Faibussowitsch   PetscCall(DMClone(base,&basec));
46709566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmVecIn,basec));
46710a96aa3bSJed Brown   if (sfRed) {
46729566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
46730a96aa3bSJed Brown     vecInLocal = vecIn;
46740a96aa3bSJed Brown   } else {
46759566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(basec,&vecInLocal));
46769566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(basec,vecIn,INSERT_VALUES,vecInLocal));
46779566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(basec,vecIn,INSERT_VALUES,vecInLocal));
46780a96aa3bSJed Brown   }
46790a96aa3bSJed Brown 
46809566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmIn,&vecOutLocal));
46810a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
46820a96aa3bSJed Brown     PetscSF            basetocoarse;
46830a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
46840a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
46850a96aa3bSJed Brown     PetscMPIInt        rank;
46860a96aa3bSJed Brown     PetscSFNode       *remotes;
46870a96aa3bSJed Brown     PetscSection       secIn, secOut;
46880a96aa3bSJed Brown     PetscInt          *remoteOffsets;
46890a96aa3bSJed Brown     PetscSF            transferSF;
46900a96aa3bSJed Brown     const PetscScalar *inArray;
46910a96aa3bSJed Brown     PetscScalar       *outArray;
46920a96aa3bSJed Brown 
46939566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
46949566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(basec, &bStart, &bEnd));
46950a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
46969566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &iStart, &iEnd));
46970a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
46980a96aa3bSJed Brown 
46999566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &remotes));
47000a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
47010a96aa3bSJed Brown       PetscInt index;
47020a96aa3bSJed Brown 
47030a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
47049566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(subpointMap, leaf, &index));
47050a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
47060a96aa3bSJed Brown     }
47070a96aa3bSJed Brown 
47089566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
47099566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
47109566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(basetocoarse));
47119566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(basec,&secIn));
47129566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn),&secOut));
47139566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
47149566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
47159566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
47169566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(vecOutLocal, &outArray));
47179566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecInLocal, &inArray));
47189566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
47199566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
47209566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecInLocal, &inArray));
47219566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray));
47229566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferSF));
47239566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secOut));
47249566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&basetocoarse));
47250a96aa3bSJed Brown   }
47269566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecInLocal));
47279566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&basec));
47289566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecIn));
47290a96aa3bSJed Brown 
47300a96aa3bSJed Brown   /* output */
47310a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
47320a96aa3bSJed Brown     Vec vecOut1, vecOut2;
47330a96aa3bSJed Brown     DM  fineDM;
47340a96aa3bSJed Brown 
47359566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmIn,&vecOut1));
47369566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut1));
47379566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal));
47380a96aa3bSJed Brown     for (i = 1; i < n_hi-1; i++) {
47390a96aa3bSJed Brown       fineDM  = hierarchy[i];
47409566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(fineDM,&vecOut2));
47419566063dSJacob Faibussowitsch       PetscCall(DMForestTransferVec(dmIn,vecOut1,fineDM,vecOut2,PETSC_TRUE,0.0));
47429566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1));
47430a96aa3bSJed Brown       vecOut1 = vecOut2;
47440a96aa3bSJed Brown       dmIn    = fineDM;
47450a96aa3bSJed Brown     }
47469566063dSJacob Faibussowitsch     PetscCall(DMForestTransferVec(dmIn,vecOut1,dm,vecOut,PETSC_TRUE,0.0));
47479566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1));
47480a96aa3bSJed Brown   } else {
47499566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut));
47509566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal));
47510a96aa3bSJed Brown   }
47529566063dSJacob Faibussowitsch   PetscCall(PetscFree2(hierarchy,hierarchy_forest));
47530a96aa3bSJed Brown   PetscFunctionReturn(0);
47540a96aa3bSJed Brown }
47550a96aa3bSJed Brown 
47560a96aa3bSJed Brown #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
47570a96aa3bSJed Brown static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
47580a96aa3bSJed Brown {
47590a96aa3bSJed Brown   DM             adaptIn, adaptOut, plexIn, plexOut;
47600a96aa3bSJed Brown   DM_Forest      *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
47610a96aa3bSJed Brown   PetscInt       dofPerDim[] = {1, 1, 1, 1};
47620a96aa3bSJed Brown   PetscSF        inSF = NULL, outSF = NULL;
47630a96aa3bSJed Brown   PetscInt       *inCids = NULL, *outCids = NULL;
47640a96aa3bSJed Brown   DMAdaptFlag    purposeIn, purposeOut;
47650a96aa3bSJed Brown 
47660a96aa3bSJed Brown   PetscFunctionBegin;
47670a96aa3bSJed Brown   forestOut = (DM_Forest *) dmOut->data;
47680a96aa3bSJed Brown   forestIn  = (DM_Forest *) dmIn->data;
47690a96aa3bSJed Brown 
47709566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmOut,&adaptOut));
47719566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmOut,&purposeOut));
47720a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *) adaptOut->data : NULL;
47730a96aa3bSJed Brown 
47749566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmIn,&adaptIn));
47759566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmIn,&purposeIn));
47760a96aa3bSJed Brown   forestAdaptIn  = adaptIn ? (DM_Forest *) adaptIn->data : NULL;
47770a96aa3bSJed Brown 
47780a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
47790a96aa3bSJed Brown     switch (purposeOut) {
47800a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47819566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
47829566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47830a96aa3bSJed Brown       break;
47840a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
47850a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
47869566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&outCids));
47879566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47880a96aa3bSJed Brown       break;
47890a96aa3bSJed Brown     default:
47909566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
47919566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
47929566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47939566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
47940a96aa3bSJed Brown     }
47950a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
47960a96aa3bSJed Brown     switch (purposeIn) {
47970a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47989566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&inCids));
47999566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48000a96aa3bSJed Brown       break;
48010a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
48020a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
48039566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48049566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48050a96aa3bSJed Brown       break;
48060a96aa3bSJed Brown     default:
48079566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48089566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
48099566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48109566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48110a96aa3bSJed Brown     }
48120a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Only support transfer from pre-adaptivity to post-adaptivity right now");
48139566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn,&plexIn));
48149566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmOut,&plexOut));
48150a96aa3bSJed Brown 
48169566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferVecTree(plexIn,vecIn,plexOut,vecOut,inSF,outSF,inCids,outCids,useBCs,time));
48179566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
48189566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
48199566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&inSF));
48209566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&outSF));
48219566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
48229566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
48230a96aa3bSJed Brown   PetscFunctionReturn(0);
48240a96aa3bSJed Brown }
48250a96aa3bSJed Brown 
48260a96aa3bSJed Brown #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
48270a96aa3bSJed Brown static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm,DM *cdm)
48280a96aa3bSJed Brown {
48290a96aa3bSJed Brown   DM             plex;
48300a96aa3bSJed Brown 
48310a96aa3bSJed Brown   PetscFunctionBegin;
48320a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
48339566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48349566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(plex,cdm));
48359566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)*cdm));
48360a96aa3bSJed Brown   PetscFunctionReturn(0);
48370a96aa3bSJed Brown }
48380a96aa3bSJed Brown 
48390a96aa3bSJed Brown #define VecViewLocal_pforest _append_pforest(VecViewLocal)
48400a96aa3bSJed Brown static PetscErrorCode VecViewLocal_pforest(Vec vec,PetscViewer viewer)
48410a96aa3bSJed Brown {
48420a96aa3bSJed Brown   DM             dm, plex;
48430a96aa3bSJed Brown 
48440a96aa3bSJed Brown   PetscFunctionBegin;
48459566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48469566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48479566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48489566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Local(vec,viewer));
48499566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48500a96aa3bSJed Brown   PetscFunctionReturn(0);
48510a96aa3bSJed Brown }
48520a96aa3bSJed Brown 
48530a96aa3bSJed Brown #define VecView_pforest _append_pforest(VecView)
48540a96aa3bSJed Brown static PetscErrorCode VecView_pforest(Vec vec,PetscViewer viewer)
48550a96aa3bSJed Brown {
48560a96aa3bSJed Brown   DM             dm, plex;
48570a96aa3bSJed Brown 
48580a96aa3bSJed Brown   PetscFunctionBegin;
48599566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48609566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48619566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48629566063dSJacob Faibussowitsch   PetscCall(VecView_Plex(vec,viewer));
48639566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48640a96aa3bSJed Brown   PetscFunctionReturn(0);
48650a96aa3bSJed Brown }
48660a96aa3bSJed Brown 
48670a96aa3bSJed Brown #define VecView_pforest_Native _infix_pforest(VecView,_Native)
48680a96aa3bSJed Brown static PetscErrorCode VecView_pforest_Native(Vec vec,PetscViewer viewer)
48690a96aa3bSJed Brown {
48700a96aa3bSJed Brown   DM             dm, plex;
48710a96aa3bSJed Brown 
48720a96aa3bSJed Brown   PetscFunctionBegin;
48739566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48749566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48759566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48769566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Native(vec,viewer));
48779566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48780a96aa3bSJed Brown   PetscFunctionReturn(0);
48790a96aa3bSJed Brown }
48800a96aa3bSJed Brown 
48810a96aa3bSJed Brown #define VecLoad_pforest _append_pforest(VecLoad)
48820a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest(Vec vec,PetscViewer viewer)
48830a96aa3bSJed Brown {
48840a96aa3bSJed Brown   DM             dm, plex;
48850a96aa3bSJed Brown 
48860a96aa3bSJed Brown   PetscFunctionBegin;
48879566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48889566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48899566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48909566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex(vec,viewer));
48919566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48920a96aa3bSJed Brown   PetscFunctionReturn(0);
48930a96aa3bSJed Brown }
48940a96aa3bSJed Brown 
48950a96aa3bSJed Brown #define VecLoad_pforest_Native _infix_pforest(VecLoad,_Native)
48960a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest_Native(Vec vec,PetscViewer viewer)
48970a96aa3bSJed Brown {
48980a96aa3bSJed Brown   DM             dm, plex;
48990a96aa3bSJed Brown 
49000a96aa3bSJed Brown   PetscFunctionBegin;
49019566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
49029566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49039566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
49049566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex_Native(vec,viewer));
49059566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
49060a96aa3bSJed Brown   PetscFunctionReturn(0);
49070a96aa3bSJed Brown }
49080a96aa3bSJed Brown 
49090a96aa3bSJed Brown #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
49100a96aa3bSJed Brown static PetscErrorCode DMCreateGlobalVector_pforest(DM dm,Vec *vec)
49110a96aa3bSJed Brown {
49120a96aa3bSJed Brown   PetscFunctionBegin;
49139566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector_Section_Private(dm,vec));
49149566063dSJacob Faibussowitsch   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
49159566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
49169566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
49179566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
49189566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
49190a96aa3bSJed Brown   PetscFunctionReturn(0);
49200a96aa3bSJed Brown }
49210a96aa3bSJed Brown 
49220a96aa3bSJed Brown #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
49230a96aa3bSJed Brown static PetscErrorCode DMCreateLocalVector_pforest(DM dm,Vec *vec)
49240a96aa3bSJed Brown {
49250a96aa3bSJed Brown   PetscFunctionBegin;
49269566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector_Section_Private(dm,vec));
49279566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
49280a96aa3bSJed Brown   PetscFunctionReturn(0);
49290a96aa3bSJed Brown }
49300a96aa3bSJed Brown 
49310a96aa3bSJed Brown #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
49320a96aa3bSJed Brown static PetscErrorCode DMCreateMatrix_pforest(DM dm,Mat *mat)
49330a96aa3bSJed Brown {
49340a96aa3bSJed Brown   DM             plex;
49350a96aa3bSJed Brown 
49360a96aa3bSJed Brown   PetscFunctionBegin;
49370a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49389566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49390a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only;  /* maybe this should go into forest->plex */
49409566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(plex,mat));
49419566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*mat,dm));
49420a96aa3bSJed Brown   PetscFunctionReturn(0);
49430a96aa3bSJed Brown }
49440a96aa3bSJed Brown 
49450a96aa3bSJed Brown #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
49460a96aa3bSJed Brown static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, InsertMode mode, Vec localX)
49470a96aa3bSJed Brown {
49480a96aa3bSJed Brown   DM             plex;
49490a96aa3bSJed Brown 
49500a96aa3bSJed Brown   PetscFunctionBegin;
49510a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49529566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49539566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(plex,time,funcs,ctxs,mode,localX));
49540a96aa3bSJed Brown   PetscFunctionReturn(0);
49550a96aa3bSJed Brown }
49560a96aa3bSJed Brown 
49570a96aa3bSJed Brown #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
49580a96aa3bSJed Brown 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)
49590a96aa3bSJed Brown {
49600a96aa3bSJed Brown   DM             plex;
49610a96aa3bSJed Brown 
49620a96aa3bSJed Brown   PetscFunctionBegin;
49630a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49649566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49659566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(plex,time,label,numIds,ids,Ncc,comps,funcs,ctxs,mode,localX));
49660a96aa3bSJed Brown   PetscFunctionReturn(0);
49670a96aa3bSJed Brown }
49680a96aa3bSJed Brown 
49690a96aa3bSJed Brown #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
49700a96aa3bSJed Brown PetscErrorCode DMProjectFieldLocal_pforest(DM dm, PetscReal time, Vec localU,void (**funcs) (PetscInt, PetscInt, PetscInt,
49710a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
49720a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
49730a96aa3bSJed Brown                                                                              PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),InsertMode mode, Vec localX)
49740a96aa3bSJed Brown {
49750a96aa3bSJed Brown   DM             plex;
49760a96aa3bSJed Brown 
49770a96aa3bSJed Brown   PetscFunctionBegin;
49780a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49799566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49809566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(plex,time,localU,funcs,mode,localX));
49810a96aa3bSJed Brown   PetscFunctionReturn(0);
49820a96aa3bSJed Brown }
49830a96aa3bSJed Brown 
49840a96aa3bSJed Brown #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
49850a96aa3bSJed Brown PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal *diff)
49860a96aa3bSJed Brown {
49870a96aa3bSJed Brown   DM             plex;
49880a96aa3bSJed Brown 
49890a96aa3bSJed Brown   PetscFunctionBegin;
49900a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49919566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49929566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(plex,time,funcs,ctxs,X,diff));
49930a96aa3bSJed Brown   PetscFunctionReturn(0);
49940a96aa3bSJed Brown }
49950a96aa3bSJed Brown 
49960a96aa3bSJed Brown #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
49970a96aa3bSJed Brown PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal diff[])
49980a96aa3bSJed Brown {
49990a96aa3bSJed Brown   DM             plex;
50000a96aa3bSJed Brown 
50010a96aa3bSJed Brown   PetscFunctionBegin;
50020a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50039566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50049566063dSJacob Faibussowitsch   PetscCall(DMComputeL2FieldDiff(plex,time,funcs,ctxs,X,diff));
50050a96aa3bSJed Brown   PetscFunctionReturn(0);
50060a96aa3bSJed Brown }
50070a96aa3bSJed Brown 
50080a96aa3bSJed Brown #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
50090a96aa3bSJed Brown static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
50100a96aa3bSJed Brown {
50110a96aa3bSJed Brown   DM             plex;
50120a96aa3bSJed Brown   PetscSection   section;
50130a96aa3bSJed Brown 
50140a96aa3bSJed Brown   PetscFunctionBegin;
50150a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50169566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50179566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(plex,&section));
50189566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dm,section));
50190a96aa3bSJed Brown   PetscFunctionReturn(0);
50200a96aa3bSJed Brown }
50210a96aa3bSJed Brown 
50220a96aa3bSJed Brown #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
50230a96aa3bSJed Brown static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
50240a96aa3bSJed Brown {
50250a96aa3bSJed Brown   DM             plex;
50260a96aa3bSJed Brown   Mat            mat;
502779769bd5SJed Brown   Vec            bias;
50280a96aa3bSJed Brown   PetscSection   section;
50290a96aa3bSJed Brown 
50300a96aa3bSJed Brown   PetscFunctionBegin;
50310a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50329566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50339566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(plex,&section,&mat,&bias));
50349566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm,section,mat,bias));
50350a96aa3bSJed Brown   PetscFunctionReturn(0);
50360a96aa3bSJed Brown }
50370a96aa3bSJed Brown 
50380a96aa3bSJed Brown #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
50390a96aa3bSJed Brown static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
50400a96aa3bSJed Brown {
50410a96aa3bSJed Brown   DM             plex;
50420a96aa3bSJed Brown 
50430a96aa3bSJed Brown   PetscFunctionBegin;
50440a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50459566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50469566063dSJacob Faibussowitsch   PetscCall(DMGetDimPoints(plex,dim,cStart,cEnd));
50470a96aa3bSJed Brown   PetscFunctionReturn(0);
50480a96aa3bSJed Brown }
50490a96aa3bSJed Brown 
50500a96aa3bSJed Brown /* Need to forward declare */
50510a96aa3bSJed Brown #define DMInitialize_pforest _append_pforest(DMInitialize)
50520a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
50530a96aa3bSJed Brown 
50540a96aa3bSJed Brown #define DMClone_pforest _append_pforest(DMClone)
50550a96aa3bSJed Brown static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
50560a96aa3bSJed Brown {
50570a96aa3bSJed Brown   PetscFunctionBegin;
50589566063dSJacob Faibussowitsch   PetscCall(DMClone_Forest(dm,newdm));
50599566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(*newdm));
50600a96aa3bSJed Brown   PetscFunctionReturn(0);
50610a96aa3bSJed Brown }
50620a96aa3bSJed Brown 
50630a96aa3bSJed Brown #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
50640a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
50650a96aa3bSJed Brown {
50660a96aa3bSJed Brown   DM_Forest         *forest;
50670a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50680a96aa3bSJed Brown   PetscInt          overlap;
50690a96aa3bSJed Brown 
50700a96aa3bSJed Brown   PetscFunctionBegin;
50719566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
50720a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
50730a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
50740a96aa3bSJed Brown   *cStart = 0;
50759566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
50760a96aa3bSJed Brown   if (overlap && pforest->ghost) {
50770a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
50780a96aa3bSJed Brown   } else {
50790a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
50800a96aa3bSJed Brown   }
50810a96aa3bSJed Brown   PetscFunctionReturn(0);
50820a96aa3bSJed Brown }
50830a96aa3bSJed Brown 
50840a96aa3bSJed Brown #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
50850a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
50860a96aa3bSJed Brown {
50870a96aa3bSJed Brown   DM_Forest         *forest;
50880a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50890a96aa3bSJed Brown   PetscMPIInt       rank;
50900a96aa3bSJed Brown   PetscInt          overlap;
50910a96aa3bSJed Brown   PetscInt          cStart, cEnd, cLocalStart, cLocalEnd;
50920a96aa3bSJed Brown   PetscInt          nRoots, nLeaves, *mine = NULL;
50930a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
50940a96aa3bSJed Brown   PetscSF           sf;
50950a96aa3bSJed Brown 
50960a96aa3bSJed Brown   PetscFunctionBegin;
50979566063dSJacob Faibussowitsch   PetscCall(DMForestGetCellChart(dm,&cStart,&cEnd));
50980a96aa3bSJed Brown   forest      = (DM_Forest*)         dm->data;
50990a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
51000a96aa3bSJed Brown   nRoots      = cEnd - cStart;
51010a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
51020a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
51030a96aa3bSJed Brown   nLeaves     = 0;
51049566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
51059566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
51060a96aa3bSJed Brown   if (overlap && pforest->ghost) {
51070a96aa3bSJed Brown     PetscSFNode      *mirror;
51080a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
51090a96aa3bSJed Brown     PetscInt         nMirror, nGhostPre, nSelf, q;
51100a96aa3bSJed Brown     void             **mirrorPtrs;
51110a96aa3bSJed Brown 
51120a96aa3bSJed Brown     nMirror      = (PetscInt) pforest->ghost->mirrors.elem_count;
51130a96aa3bSJed Brown     nSelf        = cLocalEnd - cLocalStart;
51140a96aa3bSJed Brown     nLeaves      = nRoots - nSelf;
51150a96aa3bSJed Brown     nGhostPre    = (PetscInt) pforest->ghost->proc_offsets[rank];
51169566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves,&mine));
51179566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves,&remote));
51189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nMirror,&mirror,nMirror,&mirrorPtrs));
51190a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t*) pforest->ghost->mirrors.array;
51200a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
51210a96aa3bSJed Brown       p4est_quadrant_t *mir = &(mirror_array[q]);
51220a96aa3bSJed Brown 
51230a96aa3bSJed Brown       mirror[q].rank  = rank;
51240a96aa3bSJed Brown       mirror[q].index = (PetscInt) mir->p.piggy3.local_num + cLocalStart;
51250a96aa3bSJed Brown       mirrorPtrs[q]   = (void*) &(mirror[q]);
51260a96aa3bSJed Brown     }
51270a96aa3bSJed Brown     PetscStackCallP4est(p4est_ghost_exchange_custom,(pforest->forest,pforest->ghost,sizeof(PetscSFNode),mirrorPtrs,remote));
51289566063dSJacob Faibussowitsch     PetscCall(PetscFree2(mirror,mirrorPtrs));
51290a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
51300a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
51310a96aa3bSJed Brown   }
51329566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&sf));
51339566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf,nRoots,nLeaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
51340a96aa3bSJed Brown   *cellSF = sf;
51350a96aa3bSJed Brown   PetscFunctionReturn(0);
51360a96aa3bSJed Brown }
51370a96aa3bSJed Brown 
51380a96aa3bSJed Brown static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS* ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void*), void **setup_ctx)
51390a96aa3bSJed Brown {
51400a96aa3bSJed Brown   DM             plex;
51410a96aa3bSJed Brown 
51420a96aa3bSJed Brown   PetscFunctionBegin;
51439566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
51449566063dSJacob Faibussowitsch   PetscCall(DMCreateNeumannOverlap_Plex(plex,ovl,J,setup,setup_ctx));
51450a96aa3bSJed Brown   if (!*setup) {
51469566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
51470a96aa3bSJed Brown     if (*setup) {
51489566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
51490a96aa3bSJed Brown     }
51500a96aa3bSJed Brown   }
51510a96aa3bSJed Brown   PetscFunctionReturn(0);
51520a96aa3bSJed Brown }
51530a96aa3bSJed Brown 
51540a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm)
51550a96aa3bSJed Brown {
51560a96aa3bSJed Brown   PetscFunctionBegin;
51570a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
51580a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
51590a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
51600a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
51610a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
51620a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
51630a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
51640a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
51650a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
51660a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
51670a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
51680a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
51690a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
51700a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
51710a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
51720a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
51730a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
51740a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
51750a96aa3bSJed Brown 
51769566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",DMConvert_plex_pforest));
51779566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",DMConvert_pforest_plex));
51789566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_pforest));
51799566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMForestGetPartitionOverlap));
51800a96aa3bSJed Brown   PetscFunctionReturn(0);
51810a96aa3bSJed Brown }
51820a96aa3bSJed Brown 
51830a96aa3bSJed Brown #define DMCreate_pforest _append_pforest(DMCreate)
51840a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
51850a96aa3bSJed Brown {
51860a96aa3bSJed Brown   DM_Forest         *forest;
51870a96aa3bSJed Brown   DM_Forest_pforest *pforest;
51880a96aa3bSJed Brown 
51890a96aa3bSJed Brown   PetscFunctionBegin;
51909566063dSJacob Faibussowitsch   PetscCall(PetscP4estInitialize());
51919566063dSJacob Faibussowitsch   PetscCall(DMCreate_Forest(dm));
51929566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(dm));
51939566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm,P4EST_DIM));
51940a96aa3bSJed Brown 
51950a96aa3bSJed Brown   /* set forest defaults */
51969566063dSJacob Faibussowitsch   PetscCall(DMForestSetTopology(dm,"unit"));
51979566063dSJacob Faibussowitsch   PetscCall(DMForestSetMinimumRefinement(dm,0));
51989566063dSJacob Faibussowitsch   PetscCall(DMForestSetInitialRefinement(dm,0));
51999566063dSJacob Faibussowitsch   PetscCall(DMForestSetMaximumRefinement(dm,P4EST_QMAXLEVEL));
52009566063dSJacob Faibussowitsch   PetscCall(DMForestSetGradeFactor(dm,2));
52019566063dSJacob Faibussowitsch   PetscCall(DMForestSetAdjacencyDimension(dm,0));
52029566063dSJacob Faibussowitsch   PetscCall(DMForestSetPartitionOverlap(dm,0));
52030a96aa3bSJed Brown 
52040a96aa3bSJed Brown   /* create p4est data */
52059566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(dm,&pforest));
52060a96aa3bSJed Brown 
52070a96aa3bSJed Brown   forest                            = (DM_Forest*) dm->data;
52080a96aa3bSJed Brown   forest->data                      = pforest;
52090a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
52100a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
52110a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
52120a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
52130a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
52140a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
52150a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
52160a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
52170a96aa3bSJed Brown   pforest->topo                     = NULL;
52180a96aa3bSJed Brown   pforest->forest                   = NULL;
52190a96aa3bSJed Brown   pforest->ghost                    = NULL;
52200a96aa3bSJed Brown   pforest->lnodes                   = NULL;
52210a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
52220a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
52230a96aa3bSJed Brown   pforest->cLocalStart              = -1;
52240a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
52250a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
52260a96aa3bSJed Brown   pforest->ghostName                = NULL;
52270a96aa3bSJed Brown   PetscFunctionReturn(0);
52280a96aa3bSJed Brown }
52290a96aa3bSJed Brown 
52300a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5231