xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 28b400f66ebc7ae0049166a2294dfcd3df27e64b)
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));
2385f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree((*topo)->tree_face_to_uniq));
2395f80ce2aSJacob Faibussowitsch   CHKERRQ(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;
253*28b400f6SJacob Faibussowitsch   PetscCheck(useMorton,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Lexicographic ordering not implemented yet");
2545f80ce2aSJacob Faibussowitsch   CHKERRQ(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;
2705f80ce2aSJacob Faibussowitsch   CHKERRQ(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);
2855f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrcmp(name,"brick",&isBrick));
2865f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrcmp(name,"shell",&isShell));
2875f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrcmp(name,"sphere",&isSphere));
2885f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscStrcmp(name,"moebius",&isMoebius));
2895f80ce2aSJacob Faibussowitsch   CHKERRQ(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) {
2965f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_size",N,&nretN,&flgN));
2975f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_periodicity",P,&nretP,&flgP));
2985f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscOptionsGetRealArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_bounds",B,&nretB,&flgB));
2995f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_use_morton_curve",&useMorton,&flgM));
3002c71b3e2SJacob Faibussowitsch       PetscCheckFalse(flgN && nretN != P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d sizes in -dm_p4est_brick_size, gave %d",P4EST_DIM,nretN);
3012c71b3e2SJacob Faibussowitsch       PetscCheckFalse(flgP && nretP != P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d periodicities in -dm_p4est_brick_periodicity, gave %d",P4EST_DIM,nretP);
3022c71b3e2SJacob Faibussowitsch       PetscCheckFalse(flgB && nretB != 2 * P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d bounds in -dm_p4est_brick_bounds, gave %d",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     }
3095f80ce2aSJacob Faibussowitsch     CHKERRQ(DMFTopologyCreateBrick_pforest(dm,N,P,B,topo,useMorton));
3100a96aa3bSJed Brown     /* the maxCell trick is not robust enough, localize on all cells if periodic */
3115f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetPeriodicity(dm,periodic,NULL,NULL,NULL));
3120a96aa3bSJed Brown   } else {
3135f80ce2aSJacob Faibussowitsch     CHKERRQ(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;
3180a96aa3bSJed Brown     if (isMoebius) {
3195f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetCoordinateDim(dm,3));
3200a96aa3bSJed Brown     }
3210a96aa3bSJed Brown #if defined(P4_TO_P8)
3220a96aa3bSJed Brown     if (isShell) {
3230a96aa3bSJed Brown       PetscReal R2 = 1., R1 = .55;
3240a96aa3bSJed Brown 
3250a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3265f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_outer_radius",&R2,NULL));
3275f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_inner_radius",&R1,NULL));
3280a96aa3bSJed Brown       }
3290a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_shell,((*topo)->conn,R2,R1));
3300a96aa3bSJed Brown     } else if (isSphere) {
3310a96aa3bSJed Brown       PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856;
3320a96aa3bSJed Brown 
3330a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3345f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_outer_radius",&R2,NULL));
3355f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_inner_radius",&R1,NULL));
3365f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_core_radius",&R0,NULL));
3370a96aa3bSJed Brown       }
3380a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_sphere,((*topo)->conn,R2,R1,R0));
3390a96aa3bSJed Brown     }
3400a96aa3bSJed Brown #endif
3415f80ce2aSJacob Faibussowitsch     CHKERRQ(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq));
3420a96aa3bSJed Brown   }
3430a96aa3bSJed Brown   PetscFunctionReturn(0);
3440a96aa3bSJed Brown }
3450a96aa3bSJed Brown 
3460a96aa3bSJed Brown #define DMConvert_plex_pforest _append_pforest(DMConvert_plex)
3470a96aa3bSJed Brown static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest)
3480a96aa3bSJed Brown {
3490a96aa3bSJed Brown   MPI_Comm       comm;
3500a96aa3bSJed Brown   PetscBool      isPlex;
3510a96aa3bSJed Brown   PetscInt       dim;
3520a96aa3bSJed Brown   void           *ctx;
3530a96aa3bSJed Brown 
3540a96aa3bSJed Brown   PetscFunctionBegin;
3550a96aa3bSJed Brown 
3560a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3570a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
3585f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex));
359*28b400f6SJacob Faibussowitsch   PetscCheck(isPlex,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPLEX,((PetscObject)dm)->type_name);
3605f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm,&dim));
3612c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dim != P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %d",P4EST_DIM,dim);
3625f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreate(comm,pforest));
3635f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetType(*pforest,DMPFOREST));
3645f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestSetBaseDM(*pforest,dm));
3655f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetApplicationContext(dm,&ctx));
3665f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetApplicationContext(*pforest,ctx));
3675f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCopyDisc(dm,*pforest));
3680a96aa3bSJed Brown   PetscFunctionReturn(0);
3690a96aa3bSJed Brown }
3700a96aa3bSJed Brown 
3710a96aa3bSJed Brown #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
3720a96aa3bSJed Brown static PetscErrorCode DMForestDestroy_pforest(DM dm)
3730a96aa3bSJed Brown {
3740a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
3750a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
3760a96aa3bSJed Brown 
3770a96aa3bSJed Brown   PetscFunctionBegin;
3780a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3790a96aa3bSJed Brown   if (pforest->lnodes) PetscStackCallP4est(p4est_lnodes_destroy,(pforest->lnodes));
3800a96aa3bSJed Brown   pforest->lnodes = NULL;
3810a96aa3bSJed Brown   if (pforest->ghost) PetscStackCallP4est(p4est_ghost_destroy,(pforest->ghost));
3820a96aa3bSJed Brown   pforest->ghost = NULL;
3830a96aa3bSJed Brown   if (pforest->forest) PetscStackCallP4est(p4est_destroy,(pforest->forest));
3840a96aa3bSJed Brown   pforest->forest = NULL;
3855f80ce2aSJacob Faibussowitsch   CHKERRQ(DMFTopologyDestroy_pforest(&pforest->topo));
3865f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",NULL));
3875f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",NULL));
3885f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",NULL));
3895f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(pforest->ghostName));
3905f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&pforest->plex));
3915f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
3925f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
3935f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(pforest->pointAdaptToSelfCids));
3945f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(pforest->pointSelfToAdaptCids));
3955f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(forest->data));
3960a96aa3bSJed Brown   PetscFunctionReturn(0);
3970a96aa3bSJed Brown }
3980a96aa3bSJed Brown 
3990a96aa3bSJed Brown #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
4000a96aa3bSJed Brown static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm)
4010a96aa3bSJed Brown {
4020a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4030a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest*) ((DM_Forest*) tdm->data)->data;
4040a96aa3bSJed Brown 
4050a96aa3bSJed Brown   PetscFunctionBegin;
4060a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
4075f80ce2aSJacob Faibussowitsch   CHKERRQ(DMFTopologyDestroy_pforest(&(tpforest->topo)));
4080a96aa3bSJed Brown   tpforest->topo = pforest->topo;
4090a96aa3bSJed Brown   PetscFunctionReturn(0);
4100a96aa3bSJed Brown }
4110a96aa3bSJed Brown 
4120a96aa3bSJed Brown #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
4130a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM,p4est_connectivity_t**,PetscInt**);
4140a96aa3bSJed Brown 
4150a96aa3bSJed Brown typedef struct _PforestAdaptCtx
4160a96aa3bSJed Brown {
4170a96aa3bSJed Brown   PetscInt  maxLevel;
4180a96aa3bSJed Brown   PetscInt  minLevel;
4190a96aa3bSJed Brown   PetscInt  currLevel;
4200a96aa3bSJed Brown   PetscBool anyChange;
4210a96aa3bSJed Brown }
4220a96aa3bSJed Brown PforestAdaptCtx;
4230a96aa3bSJed Brown 
4240a96aa3bSJed Brown static int pforest_coarsen_currlevel(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4250a96aa3bSJed Brown {
4260a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx*) p4est->user_pointer;
4270a96aa3bSJed Brown   PetscInt        minLevel  = ctx->minLevel;
4280a96aa3bSJed Brown   PetscInt        currLevel = ctx->currLevel;
4290a96aa3bSJed Brown 
4300a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4310a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level == currLevel);
4320a96aa3bSJed Brown }
4330a96aa3bSJed Brown 
4340a96aa3bSJed Brown static int pforest_coarsen_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4350a96aa3bSJed Brown {
4360a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4370a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4380a96aa3bSJed Brown 
4390a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level > minLevel);
4400a96aa3bSJed Brown }
4410a96aa3bSJed Brown 
4420a96aa3bSJed Brown static int pforest_coarsen_flag_any(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4430a96aa3bSJed Brown {
4440a96aa3bSJed Brown   PetscInt        i;
4450a96aa3bSJed Brown   PetscBool       any      = PETSC_FALSE;
4460a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4470a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4480a96aa3bSJed Brown 
4490a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4500a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4510a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
4520a96aa3bSJed Brown       any = PETSC_FALSE;
4530a96aa3bSJed Brown       break;
4540a96aa3bSJed Brown     }
4550a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
4560a96aa3bSJed Brown       any = PETSC_TRUE;
4570a96aa3bSJed Brown       break;
4580a96aa3bSJed Brown     }
4590a96aa3bSJed Brown   }
4600a96aa3bSJed Brown   return any ? 1 : 0;
4610a96aa3bSJed Brown }
4620a96aa3bSJed Brown 
4630a96aa3bSJed Brown static int pforest_coarsen_flag_all(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4640a96aa3bSJed Brown {
4650a96aa3bSJed Brown   PetscInt        i;
4660a96aa3bSJed Brown   PetscBool       all      = PETSC_TRUE;
4670a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4680a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4690a96aa3bSJed Brown 
4700a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4710a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4720a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
4730a96aa3bSJed Brown       all = PETSC_FALSE;
4740a96aa3bSJed Brown       break;
4750a96aa3bSJed Brown     }
4760a96aa3bSJed Brown   }
4770a96aa3bSJed Brown   return all ? 1 : 0;
4780a96aa3bSJed Brown }
4790a96aa3bSJed Brown 
4800a96aa3bSJed Brown static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4810a96aa3bSJed Brown {
4820a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
4830a96aa3bSJed Brown }
4840a96aa3bSJed Brown 
4850a96aa3bSJed Brown static int pforest_refine_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4860a96aa3bSJed Brown {
4870a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4880a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
4890a96aa3bSJed Brown 
4900a96aa3bSJed Brown   return ((PetscInt) quadrant->level < maxLevel);
4910a96aa3bSJed Brown }
4920a96aa3bSJed Brown 
4930a96aa3bSJed Brown static int pforest_refine_flag(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4940a96aa3bSJed Brown {
4950a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4960a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
4970a96aa3bSJed Brown 
4980a96aa3bSJed Brown   if ((PetscInt) quadrant->level >= maxLevel) return 0;
4990a96aa3bSJed Brown 
5000a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
5010a96aa3bSJed Brown }
5020a96aa3bSJed Brown 
5030a96aa3bSJed 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)
5040a96aa3bSJed Brown {
5050a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
5060a96aa3bSJed Brown   p4est_topidx_t t;
5070a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
5080a96aa3bSJed Brown 
5090a96aa3bSJed Brown   PetscFunctionBegin;
5100a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
5110a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t*) p4estFrom->trees->array)[t]);
5120a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t*) p4estTo->trees->array)[t]);
5130a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
5140a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
5150a96aa3bSJed Brown     PetscInt         numFrom    = (PetscInt) treeFrom->quadrants.elem_count;
5160a96aa3bSJed Brown     PetscInt         numTo      = (PetscInt) treeTo->quadrants.elem_count;
5170a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t*) treeFrom->quadrants.array;
5180a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t*) treeTo->quadrants.array;
5190a96aa3bSJed Brown     PetscInt         currentFrom, currentTo;
5200a96aa3bSJed Brown     PetscInt         treeOffsetFrom = (PetscInt) treeFrom->quadrants_offset;
5210a96aa3bSJed Brown     PetscInt         treeOffsetTo   = (PetscInt) treeTo->quadrants_offset;
5220a96aa3bSJed Brown     int              comp;
5230a96aa3bSJed Brown 
5240a96aa3bSJed Brown     PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(firstFrom,firstTo));
525*28b400f6SJacob Faibussowitsch     PetscCheck(comp,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"non-matching partitions");
5260a96aa3bSJed Brown 
5270a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
5280a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
5290a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
5300a96aa3bSJed Brown 
5310a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
5320a96aa3bSJed Brown         if (toLeaves) {
5330a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5340a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
5350a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5360a96aa3bSJed Brown         }
5370a96aa3bSJed Brown         toFineLeaves++;
5380a96aa3bSJed Brown         currentFrom++;
5390a96aa3bSJed Brown         currentTo++;
5400a96aa3bSJed Brown       } else {
5410a96aa3bSJed Brown         int fromIsAncestor;
5420a96aa3bSJed Brown 
5430a96aa3bSJed Brown         PetscStackCallP4estReturn(fromIsAncestor,p4est_quadrant_is_ancestor,(quadFrom,quadTo));
5440a96aa3bSJed Brown         if (fromIsAncestor) {
5450a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5460a96aa3bSJed Brown 
5470a96aa3bSJed Brown           if (toLeaves) {
5480a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5490a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
5500a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5510a96aa3bSJed Brown           }
5520a96aa3bSJed Brown           toFineLeaves++;
5530a96aa3bSJed Brown           currentTo++;
5540a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadFrom,&lastDesc,quadTo->level));
5550a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadTo,&lastDesc));
5560a96aa3bSJed Brown           if (comp) currentFrom++;
5570a96aa3bSJed Brown         } else {
5580a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5590a96aa3bSJed Brown 
5600a96aa3bSJed Brown           if (fromLeaves) {
5610a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
5620a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
5630a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
5640a96aa3bSJed Brown           }
5650a96aa3bSJed Brown           fromFineLeaves++;
5660a96aa3bSJed Brown           currentFrom++;
5670a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadTo,&lastDesc,quadFrom->level));
5680a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadFrom,&lastDesc));
5690a96aa3bSJed Brown           if (comp) currentTo++;
5700a96aa3bSJed Brown         }
5710a96aa3bSJed Brown       }
5720a96aa3bSJed Brown     }
5730a96aa3bSJed Brown   }
5740a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
5750a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
5760a96aa3bSJed Brown   PetscFunctionReturn(0);
5770a96aa3bSJed Brown }
5780a96aa3bSJed Brown 
5790a96aa3bSJed Brown /* Compute the maximum level across all the trees */
5800a96aa3bSJed Brown static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev)
5810a96aa3bSJed Brown {
5820a96aa3bSJed Brown   p4est_topidx_t    t, flt, llt;
5830a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
5840a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
5850a96aa3bSJed Brown   PetscInt          maxlevelloc = 0;
5860a96aa3bSJed Brown   p4est_t           *p4est;
5870a96aa3bSJed Brown 
5880a96aa3bSJed Brown   PetscFunctionBegin;
589*28b400f6SJacob Faibussowitsch   PetscCheck(pforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing DM_Forest_pforest");
590*28b400f6SJacob Faibussowitsch   PetscCheck(pforest->forest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing p4est_t");
5910a96aa3bSJed Brown   p4est = pforest->forest;
5920a96aa3bSJed Brown   flt   = p4est->first_local_tree;
5930a96aa3bSJed Brown   llt   = p4est->last_local_tree;
5940a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
5950a96aa3bSJed Brown     p4est_tree_t *tree  = &(((p4est_tree_t*) p4est->trees->array)[t]);
5960a96aa3bSJed Brown     maxlevelloc = PetscMax((PetscInt)tree->maxlevel,maxlevelloc);
5970a96aa3bSJed Brown   }
5985f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPIU_Allreduce(&maxlevelloc,lev,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
5990a96aa3bSJed Brown   PetscFunctionReturn(0);
6000a96aa3bSJed Brown }
6010a96aa3bSJed Brown 
6020a96aa3bSJed Brown /* Puts identity in coarseToFine */
6030a96aa3bSJed Brown /* assumes a matching partition */
6040a96aa3bSJed Brown static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine)
6050a96aa3bSJed Brown {
6060a96aa3bSJed Brown   p4est_topidx_t flt, llt;
6070a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
6080a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
6090a96aa3bSJed Brown   PetscInt       *fromLeaves = NULL, *toLeaves = NULL;
6100a96aa3bSJed Brown   PetscSFNode    *fromRoots  = NULL, *toRoots = NULL;
6110a96aa3bSJed Brown 
6120a96aa3bSJed Brown   PetscFunctionBegin;
6130a96aa3bSJed Brown   flt  = p4estFrom->first_local_tree;
6140a96aa3bSJed Brown   llt  = p4estFrom->last_local_tree;
6155f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFCreate(comm,&fromCoarse));
6160a96aa3bSJed Brown   if (toCoarseFromFine) {
6175f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreate(comm,&toCoarse));
6180a96aa3bSJed Brown   }
6190a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
6200a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
6215f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,NULL,NULL,&numLeavesFrom,NULL,NULL));
6225f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(numLeavesTo,&toLeaves));
6235f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(numLeavesTo,&fromRoots));
6240a96aa3bSJed Brown   if (toCoarseFromFine) {
6255f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numLeavesFrom,&fromLeaves));
6265f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(numLeavesFrom,&fromRoots));
6270a96aa3bSJed Brown   }
6285f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,toLeaves,fromRoots,&numLeavesFrom,fromLeaves,toRoots));
6290a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
6305f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(toLeaves));
6315f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,NULL,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER));
6320a96aa3bSJed Brown   } else { /* generic */
6335f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,toLeaves,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER));
6340a96aa3bSJed Brown   }
6350a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
6360a96aa3bSJed Brown   if (toCoarseFromFine) {
6375f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetGraph(toCoarse,numRootsTo,numLeavesFrom,fromLeaves,PETSC_OWN_POINTER,toRoots,PETSC_OWN_POINTER));
6380a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
6390a96aa3bSJed Brown   }
6400a96aa3bSJed Brown   PetscFunctionReturn(0);
6410a96aa3bSJed Brown }
6420a96aa3bSJed Brown 
6430a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
6440a96aa3bSJed Brown static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB)
6450a96aa3bSJed Brown {
6460a96aa3bSJed Brown   p4est_quadrant_t * myCoarseStart = &(p4estA->global_first_position[rank]);
6470a96aa3bSJed Brown   p4est_quadrant_t * myCoarseEnd   = &(p4estA->global_first_position[rank+1]);
6480a96aa3bSJed Brown   p4est_quadrant_t * globalFirstB  = p4estB->global_first_position;
6490a96aa3bSJed Brown 
6500a96aa3bSJed Brown   PetscFunctionBegin;
6510a96aa3bSJed Brown   *startB = -1;
6520a96aa3bSJed Brown   *endB   = -1;
6530a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
6540a96aa3bSJed Brown     PetscInt lo, hi, guess;
6550a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
6560a96aa3bSJed Brown     lo    = 0;
6570a96aa3bSJed Brown     hi    = size;
6580a96aa3bSJed Brown     guess = rank;
6590a96aa3bSJed Brown     while (1) {
6600a96aa3bSJed Brown       int startCompMy, myCompEnd;
6610a96aa3bSJed Brown 
6620a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseStart));
6630a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseStart,&globalFirstB[guess+1]));
6640a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
6650a96aa3bSJed Brown         *startB = guess;
6660a96aa3bSJed Brown         break;
6670a96aa3bSJed Brown       } else if (startCompMy > 0) {  /* guess is to high */
6680a96aa3bSJed Brown         hi = guess;
6690a96aa3bSJed Brown       } else { /* guess is to low */
6700a96aa3bSJed Brown         lo = guess + 1;
6710a96aa3bSJed Brown       }
6720a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6730a96aa3bSJed Brown     }
6740a96aa3bSJed Brown     /* reset bounds, but not guess */
6750a96aa3bSJed Brown     lo = 0;
6760a96aa3bSJed Brown     hi = size;
6770a96aa3bSJed Brown     while (1) {
6780a96aa3bSJed Brown       int startCompMy, myCompEnd;
6790a96aa3bSJed Brown 
6800a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseEnd));
6810a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseEnd,&globalFirstB[guess+1]));
6820a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
6830a96aa3bSJed Brown         *endB = guess + 1;
6840a96aa3bSJed Brown         break;
6850a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
6860a96aa3bSJed Brown         hi = guess;
6870a96aa3bSJed Brown       } else { /* guess is to low */
6880a96aa3bSJed Brown         lo = guess + 1;
6890a96aa3bSJed Brown       }
6900a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6910a96aa3bSJed Brown     }
6920a96aa3bSJed Brown   }
6930a96aa3bSJed Brown   PetscFunctionReturn(0);
6940a96aa3bSJed Brown }
6950a96aa3bSJed Brown 
6960a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM,DM*);
6970a96aa3bSJed Brown 
6980a96aa3bSJed Brown #define DMSetUp_pforest _append_pforest(DMSetUp)
6990a96aa3bSJed Brown static PetscErrorCode DMSetUp_pforest(DM dm)
7000a96aa3bSJed Brown {
7010a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
7020a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
7030a96aa3bSJed Brown   DM                base, adaptFrom;
7040a96aa3bSJed Brown   DMForestTopology  topoName;
7050a96aa3bSJed Brown   PetscSF           preCoarseToFine = NULL, coarseToPreFine = NULL;
7060a96aa3bSJed Brown   PforestAdaptCtx   ctx;
7070a96aa3bSJed Brown 
7080a96aa3bSJed Brown   PetscFunctionBegin;
7090a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
7100a96aa3bSJed Brown   ctx.maxLevel  = 0;
7110a96aa3bSJed Brown   ctx.currLevel = 0;
7120a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
7130a96aa3bSJed Brown   /* sanity check */
7145f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetAdaptivityForest(dm,&adaptFrom));
7155f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetBaseDM(dm,&base));
7165f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetTopology(dm,&topoName));
7172c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!adaptFrom && !base && !topoName,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"A forest needs a topology, a base DM, or a DM to adapt from");
7180a96aa3bSJed Brown 
7190a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
7200a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
7210a96aa3bSJed Brown     PetscBool         ispforest;
7220a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
7230a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
7240a96aa3bSJed Brown 
7255f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectTypeCompare((PetscObject)adaptFrom,DMPFOREST,&ispforest));
726*28b400f6SJacob Faibussowitsch     PetscCheck(ispforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Trying to adapt from %s, which is not %s",((PetscObject)adaptFrom)->type_name,DMPFOREST);
727*28b400f6SJacob Faibussowitsch     PetscCheck(apforest->topo,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"The pre-adaptation forest must have a topology");
7285f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetUp(adaptFrom));
7295f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetBaseDM(dm,&base));
7305f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetTopology(dm,&topoName));
7310a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
7320a96aa3bSJed Brown     PetscBool isPlex, isDA;
7330a96aa3bSJed Brown 
7345f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectGetName((PetscObject)base,&topoName));
7355f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestSetTopology(dm,topoName));
7365f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectTypeCompare((PetscObject)base,DMPLEX,&isPlex));
7375f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectTypeCompare((PetscObject)base,DMDA,&isDA));
7380a96aa3bSJed Brown     if (isPlex) {
7390a96aa3bSJed Brown       MPI_Comm             comm = PetscObjectComm((PetscObject)dm);
7400a96aa3bSJed Brown       PetscInt             depth;
7410a96aa3bSJed Brown       PetscMPIInt          size;
7420a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
7430a96aa3bSJed Brown       DMFTopology_pforest  *topo;
7440a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
7450a96aa3bSJed Brown 
7465f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetDepth(base,&depth));
7470a96aa3bSJed Brown       if (depth == 1) {
7480a96aa3bSJed Brown         DM connDM;
7490a96aa3bSJed Brown 
7505f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexInterpolate(base,&connDM));
7510a96aa3bSJed Brown         base = connDM;
7525f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestSetBaseDM(dm,base));
7535f80ce2aSJacob Faibussowitsch         CHKERRQ(DMDestroy(&connDM));
7542c71b3e2SJacob Faibussowitsch       } else PetscCheckFalse(depth != P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Base plex is neither interpolated nor uninterpolated? depth %D, expected 2 or %d",depth,P4EST_DIM + 1);
7555f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Comm_size(comm,&size));
7560a96aa3bSJed Brown       if (size > 1) {
7570a96aa3bSJed Brown         DM      dmRedundant;
7580a96aa3bSJed Brown         PetscSF sf;
7590a96aa3bSJed Brown 
7605f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetRedundantDM(base,&sf,&dmRedundant));
761*28b400f6SJacob Faibussowitsch         PetscCheck(dmRedundant,comm,PETSC_ERR_PLIB,"Could not create redundant DM");
7625f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscObjectCompose((PetscObject)dmRedundant,"_base_migration_sf",(PetscObject)sf));
7635f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFDestroy(&sf));
7640a96aa3bSJed Brown         base = dmRedundant;
7655f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestSetBaseDM(dm,base));
7665f80ce2aSJacob Faibussowitsch         CHKERRQ(DMDestroy(&dmRedundant));
7670a96aa3bSJed Brown       }
7685f80ce2aSJacob Faibussowitsch       CHKERRQ(DMViewFromOptions(base,NULL,"-dm_p4est_base_view"));
7695f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexCreateConnectivity_pforest(base,&conn,&tree_face_to_uniq));
7705f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscNewLog(dm,&topo));
7710a96aa3bSJed Brown       topo->refct = 1;
7720a96aa3bSJed Brown       topo->conn  = conn;
7730a96aa3bSJed Brown       topo->geom  = NULL;
7740a96aa3bSJed Brown       {
7750a96aa3bSJed Brown         PetscErrorCode (*map)(DM,PetscInt,PetscInt,const PetscReal[],PetscReal[],void*);
7760a96aa3bSJed Brown         void           *mapCtx;
7770a96aa3bSJed Brown 
7785f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx));
7790a96aa3bSJed Brown         if (map) {
7800a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
7810a96aa3bSJed Brown           p4est_geometry_t           *geom;
7820a96aa3bSJed Brown 
7835f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscNew(&geom_pforest));
7845f80ce2aSJacob Faibussowitsch           CHKERRQ(DMGetCoordinateDim(dm,&geom_pforest->coordDim));
7850a96aa3bSJed Brown           geom_pforest->map    = map;
7860a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
7870a96aa3bSJed Brown           PetscStackCallP4estReturn(geom_pforest->inner,p4est_geometry_new_connectivity,(conn));
7885f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscNew(&geom));
7890a96aa3bSJed Brown           geom->name    = topoName;
7900a96aa3bSJed Brown           geom->user    = geom_pforest;
7910a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
7920a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
7930a96aa3bSJed Brown           topo->geom    = geom;
7940a96aa3bSJed Brown         }
7950a96aa3bSJed Brown       }
7960a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
7970a96aa3bSJed Brown       pforest->topo           = topo;
798*28b400f6SJacob Faibussowitsch     } else PetscCheck(!isDA,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Not implemented yet");
7990a96aa3bSJed Brown #if 0
8000a96aa3bSJed Brown       PetscInt N[3], P[3];
8010a96aa3bSJed Brown 
8020a96aa3bSJed Brown       /* get the sizes, periodicities */
8030a96aa3bSJed Brown       /* ... */
8040a96aa3bSJed Brown                                                                   /* don't use Morton order */
8055f80ce2aSJacob Faibussowitsch       CHKERRQ(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE));
8060a96aa3bSJed Brown #endif
8070a96aa3bSJed Brown     {
8080a96aa3bSJed Brown       PetscInt numLabels, l;
8090a96aa3bSJed Brown 
8105f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetNumLabels(base,&numLabels));
8110a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
8120a96aa3bSJed Brown         PetscBool  isDepth, isGhost, isVTK, isDim, isCellType;
8130a96aa3bSJed Brown         DMLabel    label, labelNew;
8140a96aa3bSJed Brown         PetscInt   defVal;
8150a96aa3bSJed Brown         const char *name;
8160a96aa3bSJed Brown 
8175f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetLabelName(base, l, &name));
8185f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetLabelByNum(base, l, &label));
8195f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"depth",&isDepth));
8200a96aa3bSJed Brown         if (isDepth) continue;
8215f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"dim",&isDim));
8220a96aa3bSJed Brown         if (isDim) continue;
8235f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"celltype",&isCellType));
8240a96aa3bSJed Brown         if (isCellType) continue;
8255f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"ghost",&isGhost));
8260a96aa3bSJed Brown         if (isGhost) continue;
8275f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"vtk",&isVTK));
8280a96aa3bSJed Brown         if (isVTK) continue;
8295f80ce2aSJacob Faibussowitsch         CHKERRQ(DMCreateLabel(dm,name));
8305f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetLabel(dm,name,&labelNew));
8315f80ce2aSJacob Faibussowitsch         CHKERRQ(DMLabelGetDefaultValue(label,&defVal));
8325f80ce2aSJacob Faibussowitsch         CHKERRQ(DMLabelSetDefaultValue(labelNew,defVal));
8330a96aa3bSJed Brown       }
8340a96aa3bSJed Brown       /* map dm points (internal plex) to base
8350a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
8360a96aa3bSJed Brown          and propagating back to the coarsest
8370a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
8380a96aa3bSJed Brown          during DMForestTransferVecFromBase */
8395f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestGetMinimumRefinement(dm,&l));
8400a96aa3bSJed Brown       if (!l) {
8415f80ce2aSJacob Faibussowitsch         CHKERRQ(DMCreateLabel(dm,"_forest_base_subpoint_map"));
8420a96aa3bSJed Brown       }
8430a96aa3bSJed Brown     }
8440a96aa3bSJed Brown   } else { /* construct from topology name */
8450a96aa3bSJed Brown     DMFTopology_pforest *topo;
8460a96aa3bSJed Brown 
8475f80ce2aSJacob Faibussowitsch     CHKERRQ(DMFTopologyCreate_pforest(dm,topoName,&topo));
8480a96aa3bSJed Brown     pforest->topo = topo;
8490a96aa3bSJed Brown     /* TODO: construct base? */
8500a96aa3bSJed Brown   }
8510a96aa3bSJed Brown 
8520a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
8530a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
8540a96aa3bSJed Brown     DMLabel           adaptLabel;
8550a96aa3bSJed Brown     PetscInt          defaultValue;
8560a96aa3bSJed Brown     PetscInt          numValues, numValuesGlobal, cLocalStart, count;
8570a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
8580a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
8590a96aa3bSJed Brown     PetscBool         computeAdaptSF;
8600a96aa3bSJed Brown     p4est_topidx_t    flt, llt, t;
8610a96aa3bSJed Brown 
8620a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
8630a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
8640a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
8655f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetComputeAdaptivitySF(dm,&computeAdaptSF));
8660a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_copy,(apforest->forest, 0)); /* 0 indicates no data copying */
8675f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetAdaptivityLabel(dm,&adaptLabel));
8680a96aa3bSJed Brown     if (adaptLabel) {
8690a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
8705f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetNumValues(adaptLabel,&numValues));
8715f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Allreduce(&numValues,&numValuesGlobal,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)adaptFrom)));
8725f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetDefaultValue(adaptLabel,&defaultValue));
8730a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
8745f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
8755f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPforestGetRefinementLevel(dm,&ctx.currLevel));
8760a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8770a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_currlevel,NULL));
8780a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8790a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8800a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
8810a96aa3bSJed Brown         if (computeAdaptSF) {
8825f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL));
8830a96aa3bSJed Brown         }
8840a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */
8855f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
8860a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8870a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_uniform,NULL));
8880a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8890a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8900a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
8910a96aa3bSJed Brown         if (computeAdaptSF) {
8925f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL));
8930a96aa3bSJed Brown         }
8940a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
8955f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetMaximumRefinement(dm,&ctx.maxLevel));
8960a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8970a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_uniform,NULL));
8980a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8990a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
9000a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
9010a96aa3bSJed Brown         if (computeAdaptSF) {
9025f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,NULL));
9030a96aa3bSJed Brown         }
9040a96aa3bSJed Brown       } else if (numValuesGlobal) {
9050a96aa3bSJed Brown         p4est_t                    *p4est = pforest->forest;
9060a96aa3bSJed Brown         PetscInt                   *cellFlags;
9070a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
9080a96aa3bSJed Brown         PetscSF                    cellSF;
9090a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
9100a96aa3bSJed Brown         PetscBool                  adaptAny;
9110a96aa3bSJed Brown 
9125f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetMaximumRefinement(dm,&ctx.maxLevel));
9135f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
9145f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetAdaptivityStrategy(dm,&strategy));
9155f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrncmp(strategy,"any",3,&adaptAny));
9165f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetCellChart(adaptFrom,&cStart,&cEnd));
9175f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetCellSF(adaptFrom,&cellSF));
9185f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscMalloc1(cEnd-cStart,&cellFlags));
9195f80ce2aSJacob Faibussowitsch         for (c = cStart; c < cEnd; c++) CHKERRQ(DMLabelGetValue(adaptLabel,c,&cellFlags[c-cStart]));
9200a96aa3bSJed Brown         if (cellSF) {
9210a96aa3bSJed Brown           if (adaptAny) {
9225f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX));
9235f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX));
9240a96aa3bSJed Brown           } else {
9255f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN));
9265f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN));
9270a96aa3bSJed Brown           }
9280a96aa3bSJed Brown         }
9290a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
9300a96aa3bSJed Brown           p4est_tree_t       *tree    = &(((p4est_tree_t*) p4est->trees->array)[t]);
9310a96aa3bSJed Brown           PetscInt           numQuads = (PetscInt) tree->quadrants.elem_count, i;
9320a96aa3bSJed Brown           p4est_quadrant_t   *quads   = (p4est_quadrant_t *) tree->quadrants.array;
9330a96aa3bSJed Brown 
9340a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9350a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
9360a96aa3bSJed Brown             q->p.user_int = cellFlags[count++];
9370a96aa3bSJed Brown           }
9380a96aa3bSJed Brown         }
9395f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFree(cellFlags));
9400a96aa3bSJed Brown 
9410a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
9420a96aa3bSJed Brown         if (adaptAny) {
9430a96aa3bSJed Brown           PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_any,pforest_init_determine));
9440a96aa3bSJed Brown         } else {
9450a96aa3bSJed Brown           PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_all,pforest_init_determine));
9460a96aa3bSJed Brown         }
9470a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_flag,NULL));
9480a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
9490a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
9500a96aa3bSJed Brown         if (computeAdaptSF) {
9515f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,&coarseToPreFine));
9520a96aa3bSJed Brown         }
9530a96aa3bSJed Brown       }
9540a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
9550a96aa3bSJed Brown         p4est_tree_t       *atree    = &(((p4est_tree_t*) apforest->forest->trees->array)[t]);
9560a96aa3bSJed Brown         p4est_tree_t       *tree     = &(((p4est_tree_t*) pforest->forest->trees->array)[t]);
9570a96aa3bSJed Brown         PetscInt           anumQuads = (PetscInt) atree->quadrants.elem_count, i;
9580a96aa3bSJed Brown         PetscInt           numQuads  = (PetscInt) tree->quadrants.elem_count;
9590a96aa3bSJed Brown         p4est_quadrant_t   *aquads   = (p4est_quadrant_t *) atree->quadrants.array;
9600a96aa3bSJed Brown         p4est_quadrant_t   *quads    = (p4est_quadrant_t *) tree->quadrants.array;
9610a96aa3bSJed Brown 
9620a96aa3bSJed Brown         if (anumQuads != numQuads) {
9630a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
9640a96aa3bSJed Brown         } else {
9650a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9660a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
9670a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
9680a96aa3bSJed Brown 
9690a96aa3bSJed Brown             if (aq->level != q->level) {
9700a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
9710a96aa3bSJed Brown               break;
9720a96aa3bSJed Brown             }
9730a96aa3bSJed Brown           }
9740a96aa3bSJed Brown         }
9750a96aa3bSJed Brown         if (ctx.anyChange) {
9760a96aa3bSJed Brown           break;
9770a96aa3bSJed Brown         }
9780a96aa3bSJed Brown       }
9790a96aa3bSJed Brown     }
9800a96aa3bSJed Brown     {
9810a96aa3bSJed Brown       PetscInt numLabels, l;
9820a96aa3bSJed Brown 
9835f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetNumLabels(adaptFrom,&numLabels));
9840a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
9850a96aa3bSJed Brown         PetscBool  isDepth, isCellType, isGhost, isVTK;
9860a96aa3bSJed Brown         DMLabel    label, labelNew;
9870a96aa3bSJed Brown         PetscInt   defVal;
9880a96aa3bSJed Brown         const char *name;
9890a96aa3bSJed Brown 
9905f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetLabelName(adaptFrom, l, &name));
9915f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetLabelByNum(adaptFrom, l, &label));
9925f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"depth",&isDepth));
9930a96aa3bSJed Brown         if (isDepth) continue;
9945f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"celltype",&isCellType));
9950a96aa3bSJed Brown         if (isCellType) continue;
9965f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"ghost",&isGhost));
9970a96aa3bSJed Brown         if (isGhost) continue;
9985f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscStrcmp(name,"vtk",&isVTK));
9990a96aa3bSJed Brown         if (isVTK) continue;
10005f80ce2aSJacob Faibussowitsch         CHKERRQ(DMCreateLabel(dm,name));
10015f80ce2aSJacob Faibussowitsch         CHKERRQ(DMGetLabel(dm,name,&labelNew));
10025f80ce2aSJacob Faibussowitsch         CHKERRQ(DMLabelGetDefaultValue(label,&defVal));
10035f80ce2aSJacob Faibussowitsch         CHKERRQ(DMLabelSetDefaultValue(labelNew,defVal));
10040a96aa3bSJed Brown       }
10050a96aa3bSJed Brown     }
10060a96aa3bSJed Brown   } else { /* initial */
10070a96aa3bSJed Brown     PetscInt initLevel, minLevel;
10080a96aa3bSJed Brown 
10095f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetInitialRefinement(dm,&initLevel));
10105f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetMinimumRefinement(dm,&minLevel));
10110a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_new_ext,(PetscObjectComm((PetscObject)dm),pforest->topo->conn,
10120a96aa3bSJed Brown                                                              0,           /* minimum number of quadrants per processor */
10130a96aa3bSJed Brown                                                              initLevel,   /* level of refinement */
10140a96aa3bSJed Brown                                                              1,           /* uniform refinement */
10150a96aa3bSJed Brown                                                              0,           /* we don't allocate any per quadrant data */
10160a96aa3bSJed Brown                                                              NULL,        /* there is no special quadrant initialization */
10170a96aa3bSJed Brown                                                              (void*)dm)); /* this dm is the user context */
10180a96aa3bSJed Brown 
10190a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10200a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
10210a96aa3bSJed Brown       PetscBool  flgPattern, flgFractal;
10220a96aa3bSJed Brown       PetscInt   corner = 0;
10230a96aa3bSJed Brown       PetscInt   corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
10240a96aa3bSJed Brown       PetscReal  likelihood = 1./ P4EST_DIM;
10250a96aa3bSJed Brown       PetscInt   pattern;
10260a96aa3bSJed Brown       const char *prefix;
10270a96aa3bSJed Brown 
10285f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
10295f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscOptionsGetEList(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_pattern",DMRefinePatternName,PATTERN_COUNT,&pattern,&flgPattern));
10305f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscOptionsGetInt(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_corner",&corner,NULL));
10315f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_fractal_corners",corners,&ncorner,&flgFractal));
10325f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_hash_likelihood",&likelihood,NULL));
10330a96aa3bSJed Brown 
10340a96aa3bSJed Brown       if (flgPattern) {
10350a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
10360a96aa3bSJed Brown         PetscInt           maxLevel;
10370a96aa3bSJed Brown 
10385f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetMaximumRefinement(dm,&maxLevel));
10395f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscNewLog(dm,&ctx));
10400a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel,P4EST_QMAXLEVEL);
10410a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10420a96aa3bSJed Brown         switch (pattern) {
10430a96aa3bSJed Brown         case PATTERN_HASH:
10440a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
10450a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
10460a96aa3bSJed Brown           break;
10470a96aa3bSJed Brown         case PATTERN_CORNER:
10480a96aa3bSJed Brown           ctx->corner    = corner;
10490a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
10500a96aa3bSJed Brown           break;
10510a96aa3bSJed Brown         case PATTERN_CENTER:
10520a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Center;
10530a96aa3bSJed Brown           break;
10540a96aa3bSJed Brown         case PATTERN_FRACTAL:
10550a96aa3bSJed Brown           if (flgFractal) {
10560a96aa3bSJed Brown             PetscInt i;
10570a96aa3bSJed Brown 
10580a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
10590a96aa3bSJed Brown           } else {
10600a96aa3bSJed Brown #if !defined(P4_TO_P8)
10610a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
10620a96aa3bSJed Brown #else
10630a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
10640a96aa3bSJed Brown #endif
10650a96aa3bSJed Brown           }
10660a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
10670a96aa3bSJed Brown           break;
10680a96aa3bSJed Brown         default:
10690a96aa3bSJed Brown           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Not a valid refinement pattern");
10700a96aa3bSJed Brown         }
10710a96aa3bSJed Brown 
10720a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) ctx;
10730a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,1,ctx->refine_fn,NULL));
10740a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
10755f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFree(ctx));
10760a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
10770a96aa3bSJed Brown       }
10780a96aa3bSJed Brown     }
10790a96aa3bSJed Brown   }
10800a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
10810a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
10820a96aa3bSJed Brown 
10835f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetRefinementLevel(dm,&currLevel));
10845f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetInitialRefinement(dm,&initLevel));
10855f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetMinimumRefinement(dm,&minLevel));
10860a96aa3bSJed Brown     if (currLevel > minLevel) {
10870a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
10880a96aa3bSJed Brown       DMLabel           coarsen;
10890a96aa3bSJed Brown       DM                coarseDM;
10900a96aa3bSJed Brown 
10915f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestTemplate(dm,MPI_COMM_NULL,&coarseDM));
10925f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestSetAdaptivityPurpose(coarseDM,DM_ADAPT_COARSEN));
10935f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelCreate(PETSC_COMM_SELF, "coarsen",&coarsen));
10945f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelSetDefaultValue(coarsen,DM_ADAPT_COARSEN));
10955f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestSetAdaptivityLabel(coarseDM,coarsen));
10965f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelDestroy(&coarsen));
10975f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetCoarseDM(dm,coarseDM));
10985f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectDereference((PetscObject)coarseDM));
10990a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
11005f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestSetInitialRefinement(coarseDM,initLevel));
11015f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestSetMinimumRefinement(coarseDM,minLevel));
11020a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest*) ((DM_Forest*) coarseDM->data)->data;
11030a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
11040a96aa3bSJed Brown     }
11050a96aa3bSJed Brown   }
11060a96aa3bSJed Brown 
11070a96aa3bSJed Brown   { /* repartitioning and overlap */
11080a96aa3bSJed Brown     PetscMPIInt size, rank;
11090a96aa3bSJed Brown 
11105f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size));
11115f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
11120a96aa3bSJed Brown     if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
11130a96aa3bSJed Brown       PetscBool      copyForest   = PETSC_FALSE;
11140a96aa3bSJed Brown       p4est_t        *forest_copy = NULL;
11150a96aa3bSJed Brown       p4est_gloidx_t shipped      = 0;
11160a96aa3bSJed Brown 
11170a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
11180a96aa3bSJed Brown       if (copyForest) PetscStackCallP4estReturn(forest_copy,p4est_copy,(pforest->forest,0));
11190a96aa3bSJed Brown 
11200a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
11210a96aa3bSJed Brown         PetscStackCallP4estReturn(shipped,p4est_partition_ext,(pforest->forest,(int)pforest->partition_for_coarsening,NULL));
11220a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Non-uniform partition cases not implemented yet");
11230a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
11240a96aa3bSJed Brown       if (forest_copy) {
11250a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
11260a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
11270a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
11280a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
11290a96aa3bSJed Brown           PetscSFNode    *repartRoots;
11300a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
11310a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank+1];
11320a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
11330a96aa3bSJed Brown 
11340a96aa3bSJed Brown           numRoots  = (PetscInt) (forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
11350a96aa3bSJed Brown           numLeaves = (PetscInt) (postEnd - postStart);
11365f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPforestComputeOverlappingRanks(size,rank,pforest->forest,forest_copy,&pStart,&pEnd));
11375f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1((PetscInt) pforest->forest->local_num_quadrants,&repartRoots));
11380a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
11390a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
11400a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p+1];
11410a96aa3bSJed Brown             PetscInt       q;
11420a96aa3bSJed Brown 
11430a96aa3bSJed Brown             if (preEnd == preStart) continue;
11442c71b3e2SJacob Faibussowitsch             PetscCheckFalse(preStart > postStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Bad partition overlap computation");
11450a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
11460a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
11470a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
11480a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
11490a96aa3bSJed Brown             }
11500a96aa3bSJed Brown             partOffset = preEnd;
11510a96aa3bSJed Brown           }
11525f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFCreate(PetscObjectComm((PetscObject)dm),&repartSF));
11535f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFSetGraph(repartSF,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,repartRoots,PETSC_OWN_POINTER));
11545f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFSetUp(repartSF));
11550a96aa3bSJed Brown           if (preCoarseToFine) {
11560a96aa3bSJed Brown             PetscSF        repartSFembed, preCoarseToFineNew;
11570a96aa3bSJed Brown             PetscInt       nleaves;
11580a96aa3bSJed Brown             const PetscInt *leaves;
11590a96aa3bSJed Brown 
11605f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFSetUp(preCoarseToFine));
11615f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFGetGraph(preCoarseToFine,NULL,&nleaves,&leaves,NULL));
11620a96aa3bSJed Brown             if (leaves) {
11635f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSFCreateEmbeddedRootSF(repartSF,nleaves,leaves,&repartSFembed));
11640a96aa3bSJed Brown             } else {
11650a96aa3bSJed Brown               repartSFembed = repartSF;
11665f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscObjectReference((PetscObject)repartSFembed));
11670a96aa3bSJed Brown             }
11685f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFCompose(preCoarseToFine,repartSFembed,&preCoarseToFineNew));
11695f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFDestroy(&preCoarseToFine));
11705f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFDestroy(&repartSFembed));
11710a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
11720a96aa3bSJed Brown           }
11730a96aa3bSJed Brown           if (coarseToPreFine) {
11740a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
11750a96aa3bSJed Brown 
11765f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFCreateInverseSF(repartSF,&repartSFinv));
11775f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFCompose(repartSFinv,coarseToPreFine,&coarseToPreFineNew));
11785f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFDestroy(&coarseToPreFine));
11795f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFDestroy(&repartSFinv));
11800a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
11810a96aa3bSJed Brown           }
11825f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFDestroy(&repartSF));
11830a96aa3bSJed Brown         }
11840a96aa3bSJed Brown         PetscStackCallP4est(p4est_destroy,(forest_copy));
11850a96aa3bSJed Brown       }
11860a96aa3bSJed Brown     }
11870a96aa3bSJed Brown     if (size > 1) {
11880a96aa3bSJed Brown       PetscInt overlap;
11890a96aa3bSJed Brown 
11905f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestGetPartitionOverlap(dm,&overlap));
11910a96aa3bSJed Brown 
11920a96aa3bSJed Brown       if (adaptFrom) {
11930a96aa3bSJed Brown         PetscInt aoverlap;
11940a96aa3bSJed Brown 
11955f80ce2aSJacob Faibussowitsch         CHKERRQ(DMForestGetPartitionOverlap(adaptFrom,&aoverlap));
11960a96aa3bSJed Brown         if (aoverlap != overlap) {
11970a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
11980a96aa3bSJed Brown         }
11990a96aa3bSJed Brown       }
12000a96aa3bSJed Brown 
12010a96aa3bSJed Brown       if (overlap > 0) {
12020a96aa3bSJed Brown         PetscInt i, cLocalStart;
12030a96aa3bSJed Brown         PetscInt cEnd;
12040a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
12050a96aa3bSJed Brown 
12060a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->ghost,p4est_ghost_new,(pforest->forest,P4EST_CONNECT_FULL));
12070a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->lnodes,p4est_lnodes_new,(pforest->forest,pforest->ghost,-P4EST_DIM));
12080a96aa3bSJed Brown         PetscStackCallP4est(p4est_ghost_support_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
12090a96aa3bSJed Brown         for (i = 1; i < overlap; i++) PetscStackCallP4est(p4est_ghost_expand_by_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
12100a96aa3bSJed Brown 
12110a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
12120a96aa3bSJed Brown         cEnd        = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
12130a96aa3bSJed Brown 
12140a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
12150a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
12165f80ce2aSJacob Faibussowitsch           if (adaptFrom) CHKERRQ(DMForestGetCellSF(adaptFrom,&preCellSF));
12170a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
12185f80ce2aSJacob Faibussowitsch           CHKERRQ(DMForestGetCellSF(dm,&cellSF));
12190a96aa3bSJed Brown         }
12200a96aa3bSJed Brown         if (preCoarseToFine) {
12210a96aa3bSJed Brown           PetscSF           preCoarseToFineNew;
12220a96aa3bSJed Brown           PetscInt          nleaves, nroots, *leavesNew, i, nleavesNew;
12230a96aa3bSJed Brown           const PetscInt    *leaves;
12240a96aa3bSJed Brown           const PetscSFNode *remotes;
12250a96aa3bSJed Brown           PetscSFNode       *remotesAll;
12260a96aa3bSJed Brown 
12275f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFSetUp(preCoarseToFine));
12285f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFGetGraph(preCoarseToFine,&nroots,&nleaves,&leaves,&remotes));
12295f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1(cEnd,&remotesAll));
12300a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
12310a96aa3bSJed Brown             remotesAll[i].rank  = -1;
12320a96aa3bSJed Brown             remotesAll[i].index = -1;
12330a96aa3bSJed Brown           }
12340a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
12355f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFSetUp(cellSF));
12365f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFBcastBegin(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE));
12375f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFBcastEnd(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE));
12380a96aa3bSJed Brown           nleavesNew = 0;
12390a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12400a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
12410a96aa3bSJed Brown           }
12425f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1(nleavesNew,&leavesNew));
12430a96aa3bSJed Brown           nleavesNew = 0;
12440a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12450a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
12460a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
12470a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
12480a96aa3bSJed Brown               nleavesNew++;
12490a96aa3bSJed Brown             }
12500a96aa3bSJed Brown           }
12515f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFCreate(PetscObjectComm((PetscObject)dm),&preCoarseToFineNew));
12520a96aa3bSJed Brown           if (nleavesNew < cEnd) {
12535f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,leavesNew,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES));
12540a96aa3bSJed Brown           } else { /* all cells are leaves */
12555f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscFree(leavesNew));
12565f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,NULL,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES));
12570a96aa3bSJed Brown           }
12585f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscFree(remotesAll));
12595f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFDestroy(&preCoarseToFine));
12600a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12610a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12620a96aa3bSJed Brown         }
12630a96aa3bSJed Brown         if (coarseToPreFine) {
12640a96aa3bSJed Brown           PetscSF           coarseToPreFineNew;
12650a96aa3bSJed Brown           PetscInt          nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
12660a96aa3bSJed Brown           const PetscInt    *leaves;
12670a96aa3bSJed Brown           const PetscSFNode *remotes;
12680a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
12690a96aa3bSJed Brown 
12705f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFSetUp(coarseToPreFine));
12715f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFGetGraph(coarseToPreFine,&nroots,&nleaves,&leaves,&remotes));
12725f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFGetGraph(preCellSF,NULL,&nleavesCellSF,NULL,NULL));
12735f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1(nroots,&remotesNewRoot));
12745f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1(nleaves,&remotesNew));
12750a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
12760a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
12770a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
12780a96aa3bSJed Brown           }
12795f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFBcastBegin(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE));
12805f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFBcastEnd(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE));
12815f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscFree(remotesNewRoot));
12825f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1(nleavesCellSF,&remotesExpanded));
12830a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12840a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
12850a96aa3bSJed Brown             remotesExpanded[i].index = -1;
12860a96aa3bSJed Brown           }
12870a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
12885f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscFree(remotesNew));
12895f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFBcastBegin(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE));
12905f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFBcastEnd(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE));
12910a96aa3bSJed Brown 
12920a96aa3bSJed Brown           nleavesExpanded = 0;
12930a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12940a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
12950a96aa3bSJed Brown           }
12965f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1(nleavesExpanded,&leavesNew));
12970a96aa3bSJed Brown           nleavesExpanded = 0;
12980a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12990a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
13000a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
13010a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
13020a96aa3bSJed Brown               nleavesExpanded++;
13030a96aa3bSJed Brown             }
13040a96aa3bSJed Brown           }
13055f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFCreate(PetscObjectComm((PetscObject)dm),&coarseToPreFineNew));
13060a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
13075f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,leavesNew,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES));
13080a96aa3bSJed Brown           } else {
13095f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscFree(leavesNew));
13105f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,NULL,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES));
13110a96aa3bSJed Brown           }
13125f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscFree(remotesExpanded));
13135f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscSFDestroy(&coarseToPreFine));
13140a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
13150a96aa3bSJed Brown         }
13160a96aa3bSJed Brown       }
13170a96aa3bSJed Brown     }
13180a96aa3bSJed Brown   }
13190a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
13200a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
13210a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
13225f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Allreduce(&ctx.anyChange,&(pforest->adaptivitySuccess),1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm)));
13235f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,NULL));
13240a96aa3bSJed Brown   PetscFunctionReturn(0);
13250a96aa3bSJed Brown }
13260a96aa3bSJed Brown 
13270a96aa3bSJed Brown #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
13280a96aa3bSJed Brown static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success)
13290a96aa3bSJed Brown {
13300a96aa3bSJed Brown   DM_Forest         *forest;
13310a96aa3bSJed Brown   DM_Forest_pforest *pforest;
13320a96aa3bSJed Brown 
13330a96aa3bSJed Brown   PetscFunctionBegin;
13340a96aa3bSJed Brown   forest   = (DM_Forest *) dm->data;
13350a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *) forest->data;
13360a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
13370a96aa3bSJed Brown   PetscFunctionReturn(0);
13380a96aa3bSJed Brown }
13390a96aa3bSJed Brown 
13400a96aa3bSJed Brown #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
13410a96aa3bSJed Brown static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer)
13420a96aa3bSJed Brown {
13430a96aa3bSJed Brown   DM             dm = (DM) odm;
13440a96aa3bSJed Brown 
13450a96aa3bSJed Brown   PetscFunctionBegin;
13460a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13470a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13485f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetUp(dm));
13490a96aa3bSJed Brown   switch (viewer->format) {
13500a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
13510a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO:
13520a96aa3bSJed Brown   {
13530a96aa3bSJed Brown     PetscInt   dim;
13540a96aa3bSJed Brown     const char *name;
13550a96aa3bSJed Brown 
13565f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectGetName((PetscObject) dm, &name));
13575f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetDimension(dm, &dim));
13585f80ce2aSJacob Faibussowitsch     if (name) CHKERRQ(PetscViewerASCIIPrintf(viewer, "Forest %s in %D dimensions:\n", name, dim));
13595f80ce2aSJacob Faibussowitsch     else      CHKERRQ(PetscViewerASCIIPrintf(viewer, "Forest in %D dimensions:\n", dim));
13600a96aa3bSJed Brown   }
13610a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
13620a96aa3bSJed Brown   case PETSC_VIEWER_LOAD_BALANCE:
13630a96aa3bSJed Brown   {
13640a96aa3bSJed Brown     DM plex;
13650a96aa3bSJed Brown 
13665f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetPlex(dm, &plex));
13675f80ce2aSJacob Faibussowitsch     CHKERRQ(DMView(plex, viewer));
13680a96aa3bSJed Brown   }
13690a96aa3bSJed Brown   break;
137098921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13710a96aa3bSJed Brown   }
13720a96aa3bSJed Brown   PetscFunctionReturn(0);
13730a96aa3bSJed Brown }
13740a96aa3bSJed Brown 
13750a96aa3bSJed Brown #define DMView_VTK_pforest _append_pforest(DMView_VTK)
13760a96aa3bSJed Brown static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer)
13770a96aa3bSJed Brown {
13780a96aa3bSJed Brown   DM                dm       = (DM) odm;
13790a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
13800a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
13810a96aa3bSJed Brown   PetscBool         isvtk;
13820a96aa3bSJed Brown   PetscReal         vtkScale = 1. - PETSC_MACHINE_EPSILON;
13830a96aa3bSJed Brown   PetscViewer_VTK   *vtk     = (PetscViewer_VTK*)viewer->data;
13840a96aa3bSJed Brown   const char        *name;
13850a96aa3bSJed Brown   char              *filenameStrip = NULL;
13860a96aa3bSJed Brown   PetscBool         hasExt;
13870a96aa3bSJed Brown   size_t            len;
13880a96aa3bSJed Brown   p4est_geometry_t  *geom;
13890a96aa3bSJed Brown 
13900a96aa3bSJed Brown   PetscFunctionBegin;
13910a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13920a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13935f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetUp(dm));
13940a96aa3bSJed Brown   geom = pforest->topo->geom;
13955f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk));
1396*28b400f6SJacob Faibussowitsch   PetscCheck(isvtk,PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
13970a96aa3bSJed Brown   switch (viewer->format) {
13980a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
1399*28b400f6SJacob Faibussowitsch     PetscCheck(pforest->forest,PetscObjectComm(odm),PETSC_ERR_ARG_WRONG,"DM has not been setup with a valid forest");
14000a96aa3bSJed Brown     name = vtk->filename;
14015f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrlen(name,&len));
14025f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcasecmp(name+len-4,".vtu",&hasExt));
14030a96aa3bSJed Brown     if (hasExt) {
14045f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrallocpy(name,&filenameStrip));
14050a96aa3bSJed Brown       filenameStrip[len-4]='\0';
14060a96aa3bSJed Brown       name                = filenameStrip;
14070a96aa3bSJed Brown     }
14080a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4estReturn(geom,p4est_geometry_new_connectivity,(pforest->topo->conn));
14090a96aa3bSJed Brown     {
14100a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
14110a96aa3bSJed Brown       int                 footerr;
14120a96aa3bSJed Brown 
14130a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_context_new,(pforest->forest,name));
14140a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_geom,(pvtk,geom));
14150a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_scale,(pvtk,(double)vtkScale));
14160a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_header,(pvtk));
1417*28b400f6SJacob Faibussowitsch       PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_header() failed");
14180a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_cell_dataf,(pvtk,
14190a96aa3bSJed Brown                                                                  1, /* write tree */
14200a96aa3bSJed Brown                                                                  1, /* write level */
14210a96aa3bSJed Brown                                                                  1, /* write rank */
14220a96aa3bSJed Brown                                                                  0, /* do not wrap rank */
14230a96aa3bSJed Brown                                                                  0, /* no scalar fields */
14240a96aa3bSJed Brown                                                                  0, /* no vector fields */
14250a96aa3bSJed Brown                                                                  pvtk));
1426*28b400f6SJacob Faibussowitsch       PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_cell_dataf() failed");
14270a96aa3bSJed Brown       PetscStackCallP4estReturn(footerr,p4est_vtk_write_footer,(pvtk));
1428*28b400f6SJacob Faibussowitsch       PetscCheck(!footerr,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_footer() failed");
14290a96aa3bSJed Brown     }
14300a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4est(p4est_geometry_destroy,(geom));
14315f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(filenameStrip));
14320a96aa3bSJed Brown     break;
143398921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
14340a96aa3bSJed Brown   }
14350a96aa3bSJed Brown   PetscFunctionReturn(0);
14360a96aa3bSJed Brown }
14370a96aa3bSJed Brown 
14380a96aa3bSJed Brown #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
14390a96aa3bSJed Brown static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer)
14400a96aa3bSJed Brown {
14410a96aa3bSJed Brown   DM             plex;
14420a96aa3bSJed Brown 
14430a96aa3bSJed Brown   PetscFunctionBegin;
14445f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetUp(dm));
14455f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm, &plex));
14465f80ce2aSJacob Faibussowitsch   CHKERRQ(DMView(plex, viewer));
14470a96aa3bSJed Brown   PetscFunctionReturn(0);
14480a96aa3bSJed Brown }
14490a96aa3bSJed Brown 
14500a96aa3bSJed Brown #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
14510a96aa3bSJed Brown static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer)
14520a96aa3bSJed Brown {
14530a96aa3bSJed Brown   DM             plex;
14540a96aa3bSJed Brown 
14550a96aa3bSJed Brown   PetscFunctionBegin;
14565f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetUp(dm));
14575f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm, &plex));
14585f80ce2aSJacob Faibussowitsch   CHKERRQ(DMView(plex, viewer));
14590a96aa3bSJed Brown   PetscFunctionReturn(0);
14600a96aa3bSJed Brown }
14610a96aa3bSJed Brown 
14620a96aa3bSJed Brown #define DMView_pforest _append_pforest(DMView)
14630a96aa3bSJed Brown static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer)
14640a96aa3bSJed Brown {
14650a96aa3bSJed Brown   PetscBool      isascii, isvtk, ishdf5, isglvis;
14660a96aa3bSJed Brown 
14670a96aa3bSJed Brown   PetscFunctionBegin;
14680a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14690a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
14705f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii));
14715f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk));
14725f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5));
14735f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis));
14740a96aa3bSJed Brown   if (isascii) {
14755f80ce2aSJacob Faibussowitsch     CHKERRQ(DMView_ASCII_pforest((PetscObject) dm,viewer));
14760a96aa3bSJed Brown   } else if (isvtk) {
14775f80ce2aSJacob Faibussowitsch     CHKERRQ(DMView_VTK_pforest((PetscObject) dm,viewer));
14780a96aa3bSJed Brown   } else if (ishdf5) {
14795f80ce2aSJacob Faibussowitsch     CHKERRQ(DMView_HDF5_pforest(dm, viewer));
14800a96aa3bSJed Brown   } else if (isglvis) {
14815f80ce2aSJacob Faibussowitsch     CHKERRQ(DMView_GLVis_pforest(dm, viewer));
14820a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject) dm),PETSC_ERR_SUP,"Viewer not supported (not VTK, HDF5, or GLVis)");
14830a96aa3bSJed Brown   PetscFunctionReturn(0);
14840a96aa3bSJed Brown }
14850a96aa3bSJed Brown 
14860a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq)
14870a96aa3bSJed Brown {
14880a96aa3bSJed Brown   PetscInt       *ttf, f, t, g, count;
14890a96aa3bSJed Brown   PetscInt       numFacets;
14900a96aa3bSJed Brown 
14910a96aa3bSJed Brown   PetscFunctionBegin;
14920a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
14935f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(numFacets,&ttf));
14940a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
14950a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
14960a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
14970a96aa3bSJed Brown       if (ttf[g] == -1) {
14980a96aa3bSJed Brown         PetscInt ng;
14990a96aa3bSJed Brown 
15000a96aa3bSJed Brown         ttf[g]  = count++;
15010a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
15020a96aa3bSJed Brown         ttf[ng] = ttf[g];
15030a96aa3bSJed Brown       }
15040a96aa3bSJed Brown     }
15050a96aa3bSJed Brown   }
15060a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
15070a96aa3bSJed Brown   PetscFunctionReturn(0);
15080a96aa3bSJed Brown }
15090a96aa3bSJed Brown 
15100a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq)
15110a96aa3bSJed Brown {
15120a96aa3bSJed Brown   p4est_topidx_t       numTrees, numVerts, numCorns, numCtt;
15130a96aa3bSJed Brown   PetscSection         ctt;
15140a96aa3bSJed Brown #if defined(P4_TO_P8)
15150a96aa3bSJed Brown   p4est_topidx_t       numEdges, numEtt;
15160a96aa3bSJed Brown   PetscSection         ett;
15170a96aa3bSJed Brown   PetscInt             eStart, eEnd, e, ettSize;
15180a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES + P8EST_EDGES;
15190a96aa3bSJed Brown   PetscInt             edgeOff = 1 + P4EST_FACES;
15200a96aa3bSJed Brown #else
15210a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES;
15220a96aa3bSJed Brown #endif
15230a96aa3bSJed Brown   p4est_connectivity_t *conn;
15240a96aa3bSJed Brown   PetscInt             cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
15250a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
15260a96aa3bSJed Brown   PetscInt             *ttf;
15270a96aa3bSJed Brown 
15280a96aa3bSJed Brown   PetscFunctionBegin;
15290a96aa3bSJed Brown   /* 1: count objects, allocate */
15305f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd));
15315f80ce2aSJacob Faibussowitsch   CHKERRQ(P4estTopidxCast(cEnd-cStart,&numTrees));
15320a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
15335f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd));
15345f80ce2aSJacob Faibussowitsch   CHKERRQ(P4estTopidxCast(vEnd-vStart,&numCorns));
15355f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF,&ctt));
15365f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(ctt,vStart,vEnd));
15370a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
15380a96aa3bSJed Brown     PetscInt s;
15390a96aa3bSJed Brown 
15405f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
15410a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15420a96aa3bSJed Brown       PetscInt p = star[2*s];
15430a96aa3bSJed Brown 
15440a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15450a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
15460a96aa3bSJed Brown          * only protects against periodicity problems */
15475f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15482c71b3e2SJacob Faibussowitsch         PetscCheckFalse(closureSize != P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell %D with wrong closure size %D != %D", p, closureSize, P4EST_INSUL);
15490a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
15500a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
15510a96aa3bSJed Brown 
15522c71b3e2SJacob Faibussowitsch           PetscCheckFalse(cellVert < vStart || cellVert >= vEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: vertices");
15530a96aa3bSJed Brown           if (cellVert == v) {
15545f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionAddDof(ctt,v,1));
15550a96aa3bSJed Brown           }
15560a96aa3bSJed Brown         }
15575f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15580a96aa3bSJed Brown       }
15590a96aa3bSJed Brown     }
15605f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
15610a96aa3bSJed Brown   }
15625f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(ctt));
15635f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(ctt,&cttSize));
15645f80ce2aSJacob Faibussowitsch   CHKERRQ(P4estTopidxCast(cttSize,&numCtt));
15650a96aa3bSJed Brown #if defined(P4_TO_P8)
15665f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(dm,P4EST_DIM-1,&eStart,&eEnd));
15675f80ce2aSJacob Faibussowitsch   CHKERRQ(P4estTopidxCast(eEnd-eStart,&numEdges));
15685f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF,&ett));
15695f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(ett,eStart,eEnd));
15700a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
15710a96aa3bSJed Brown     PetscInt s;
15720a96aa3bSJed Brown 
15735f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
15740a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15750a96aa3bSJed Brown       PetscInt p = star[2*s];
15760a96aa3bSJed Brown 
15770a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15780a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
15790a96aa3bSJed Brown          * only protects against periodicity problems */
15805f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15812c71b3e2SJacob Faibussowitsch         PetscCheckFalse(closureSize != P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell with wrong closure size");
15820a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
15830a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
15840a96aa3bSJed Brown 
15852c71b3e2SJacob Faibussowitsch           PetscCheckFalse(cellEdge < eStart || cellEdge >= eEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: edges");
15860a96aa3bSJed Brown           if (cellEdge == e) {
15875f80ce2aSJacob Faibussowitsch             CHKERRQ(PetscSectionAddDof(ett,e,1));
15880a96aa3bSJed Brown           }
15890a96aa3bSJed Brown         }
15905f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15910a96aa3bSJed Brown       }
15920a96aa3bSJed Brown     }
15935f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
15940a96aa3bSJed Brown   }
15955f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(ett));
15965f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(ett,&ettSize));
15975f80ce2aSJacob Faibussowitsch   CHKERRQ(P4estTopidxCast(ettSize,&numEtt));
15980a96aa3bSJed Brown 
15990a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
16000a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p8est_connectivity_new,(numVerts,numTrees,numEdges,numEtt,numCorns,numCtt));
16010a96aa3bSJed Brown #else
16020a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p4est_connectivity_new,(numVerts,numTrees,numCorns,numCtt));
16030a96aa3bSJed Brown #endif
16040a96aa3bSJed Brown 
16050a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
16065f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(dm,1,&fStart,&fEnd));
16075f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1((cEnd-cStart) * P4EST_FACES,&ttf));
16080a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
16090a96aa3bSJed Brown     PetscInt       numSupp, s;
16100a96aa3bSJed Brown     PetscInt       myFace[2] = {-1, -1};
16110a96aa3bSJed Brown     PetscInt       myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
16120a96aa3bSJed Brown     const PetscInt *supp;
16130a96aa3bSJed Brown 
16145f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSupportSize(dm, f, &numSupp));
16152c71b3e2SJacob Faibussowitsch     PetscCheckFalse(numSupp != 1 && numSupp != 2,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"point %D has facet with %D sides: must be 1 or 2 (boundary or conformal)",f,numSupp);
16165f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSupport(dm, f, &supp));
16170a96aa3bSJed Brown 
16180a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16190a96aa3bSJed Brown       PetscInt p = supp[s];
16200a96aa3bSJed Brown 
16210a96aa3bSJed Brown       if (p >= cEnd) {
16220a96aa3bSJed Brown         numSupp--;
16230a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
16240a96aa3bSJed Brown         break;
16250a96aa3bSJed Brown       }
16260a96aa3bSJed Brown     }
16270a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16280a96aa3bSJed Brown       PetscInt       p = supp[s], i;
16290a96aa3bSJed Brown       PetscInt       numCone;
16300a96aa3bSJed Brown       DMPolytopeType ct;
16310a96aa3bSJed Brown       const PetscInt *cone;
16320a96aa3bSJed Brown       const PetscInt *ornt;
16330a96aa3bSJed Brown       PetscInt       orient = PETSC_MIN_INT;
16340a96aa3bSJed Brown 
16355f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeSize(dm, p, &numCone));
16362c71b3e2SJacob Faibussowitsch       PetscCheckFalse(numCone != P4EST_FACES,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %D has %D facets, expect %d",p,numCone,P4EST_FACES);
16375f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetCone(dm, p, &cone));
16385f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetCellType(dm, cone[0], &ct));
16395f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetConeOrientation(dm, p, &ornt));
16400a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
16410a96aa3bSJed Brown         if (cone[i] == f) {
16420a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
16430a96aa3bSJed Brown           break;
16440a96aa3bSJed Brown         }
16450a96aa3bSJed Brown       }
16462c71b3e2SJacob Faibussowitsch       PetscCheckFalse(i >= P4EST_FACES,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %D faced %D mismatch",p,f);
16470a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
16480a96aa3bSJed Brown         DMPolytopeType ct;
16495f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetCellType(dm, p, &ct));
165098921bdaSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %D (%s) should be in [%D, %D)",p,DMPolytopeTypes[ct],cStart,cEnd);
16510a96aa3bSJed Brown       }
16520a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
16530a96aa3bSJed Brown       if (numSupp == 1) {
16540a96aa3bSJed Brown         /* boundary faces indicated by self reference */
16550a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
16560a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t) PetscFaceToP4estFace[i];
16570a96aa3bSJed Brown       } else {
16580a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16590a96aa3bSJed Brown 
16600a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
16610a96aa3bSJed Brown         myFace[s] = PetscFaceToP4estFace[i];
16620a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
16630a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
16640a96aa3bSJed Brown         myOrnt[s] = DihedralCompose(N,orient,DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
16650a96aa3bSJed Brown       }
16660a96aa3bSJed Brown     }
16670a96aa3bSJed Brown     if (numSupp == 2) {
16680a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
16690a96aa3bSJed Brown         PetscInt       p = supp[s];
16700a96aa3bSJed Brown         PetscInt       orntAtoB;
16710a96aa3bSJed Brown         PetscInt       p4estOrient;
16720a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16730a96aa3bSJed Brown 
16740a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
16750a96aa3bSJed Brown          * permutation of this cell-facet's cone */
16760a96aa3bSJed Brown         orntAtoB = DihedralCompose(N,DihedralInvert(N,myOrnt[1-s]),myOrnt[s]);
16770a96aa3bSJed Brown 
16780a96aa3bSJed Brown         /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
16790a96aa3bSJed Brown          * vertices around facet) */
16800a96aa3bSJed Brown #if !defined(P4_TO_P8)
16810a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
16820a96aa3bSJed Brown #else
16830a96aa3bSJed Brown         {
16840a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
16850a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
16860a96aa3bSJed Brown 
16870a96aa3bSJed Brown                                                                                            /* swap bits */
16880a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
16890a96aa3bSJed Brown         }
16900a96aa3bSJed Brown #endif
16910a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
16920a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
16930a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t) myFace[1 - s] + p4estOrient * P4EST_FACES;
16940a96aa3bSJed Brown       }
16950a96aa3bSJed Brown     }
16960a96aa3bSJed Brown   }
16970a96aa3bSJed Brown 
16980a96aa3bSJed Brown #if defined(P4_TO_P8)
16990a96aa3bSJed Brown   /* 3: visit every edge */
17000a96aa3bSJed Brown   conn->ett_offset[0] = 0;
17010a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
17020a96aa3bSJed Brown     PetscInt off, s;
17030a96aa3bSJed Brown 
17045f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(ett,e,&off));
17050a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t) off;
17065f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
17070a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17080a96aa3bSJed Brown       PetscInt p = star[2 * s];
17090a96aa3bSJed Brown 
17100a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17115f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17122c71b3e2SJacob Faibussowitsch         PetscCheckFalse(closureSize != P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
17130a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
17140a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
17150a96aa3bSJed Brown           PetscInt cellOrnt = closure[2 * (c + edgeOff) + 1];
17160a96aa3bSJed Brown           DMPolytopeType ct;
17170a96aa3bSJed Brown 
17185f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetCellType(dm, cellEdge, &ct));
17190a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
17200a96aa3bSJed Brown           if (cellEdge == e) {
17210a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
17220a96aa3bSJed Brown             PetscInt totalOrient;
17230a96aa3bSJed Brown 
17240a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
17250a96aa3bSJed Brown             totalOrient = DihedralCompose(2,cellOrnt,DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
17260a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
17270a96aa3bSJed Brown             totalOrient             = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
17280a96aa3bSJed Brown             conn->edge_to_tree[off] = (p4est_locidx_t) (p - cStart);
17290a96aa3bSJed Brown             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standart (see
17300a96aa3bSJed Brown              * p8est_connectivity.h) */
17310a96aa3bSJed Brown             conn->edge_to_edge[off++] = (int8_t) p4estEdge + P8EST_EDGES * totalOrient;
17320a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
17330a96aa3bSJed Brown           }
17340a96aa3bSJed Brown         }
17355f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17360a96aa3bSJed Brown       }
17370a96aa3bSJed Brown     }
17385f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
17390a96aa3bSJed Brown   }
17405f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&ett));
17410a96aa3bSJed Brown #endif
17420a96aa3bSJed Brown 
17430a96aa3bSJed Brown   /* 4: visit every vertex */
17440a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
17450a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
17460a96aa3bSJed Brown     PetscInt off, s;
17470a96aa3bSJed Brown 
17485f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(ctt,v,&off));
17490a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t) off;
17505f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
17510a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17520a96aa3bSJed Brown       PetscInt p = star[2 * s];
17530a96aa3bSJed Brown 
17540a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17555f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17562c71b3e2SJacob Faibussowitsch         PetscCheckFalse(closureSize != P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
17570a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
17580a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
17590a96aa3bSJed Brown 
17600a96aa3bSJed Brown           if (cellVert == v) {
17610a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
17620a96aa3bSJed Brown 
17630a96aa3bSJed Brown             conn->corner_to_tree[off]     = (p4est_locidx_t) (p - cStart);
17640a96aa3bSJed Brown             conn->corner_to_corner[off++] = (int8_t) p4estVert;
17650a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
17660a96aa3bSJed Brown           }
17670a96aa3bSJed Brown         }
17685f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17690a96aa3bSJed Brown       }
17700a96aa3bSJed Brown     }
17715f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
17720a96aa3bSJed Brown   }
17735f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&ctt));
17740a96aa3bSJed Brown 
17750a96aa3bSJed Brown   /* 5: Compute the coordinates */
17760a96aa3bSJed Brown   {
17770a96aa3bSJed Brown     PetscInt     coordDim;
17780a96aa3bSJed Brown     Vec          coordVec;
17790a96aa3bSJed Brown     PetscSection coordSec;
17800a96aa3bSJed Brown     PetscBool    localized;
17810a96aa3bSJed Brown 
17825f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateDim(dm, &coordDim));
17835f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinatesLocal(dm, &coordVec));
17845f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinatesLocalizedLocal(dm, &localized));
17855f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateSection(dm, &coordSec));
17860a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
17870a96aa3bSJed Brown       PetscInt    dof;
17880a96aa3bSJed Brown       PetscScalar *cellCoords = NULL;
17890a96aa3bSJed Brown 
17905f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexVecGetClosure(dm, coordSec, coordVec, c, &dof, &cellCoords));
17912c71b3e2SJacob Faibussowitsch       PetscCheckFalse(!localized && dof != P4EST_CHILDREN * coordDim,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Need coordinates at the corners: (dof) %D != %D * %D (sdim)", dof, P4EST_CHILDREN, coordDim);
17920a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
17930a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
17940a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
17950a96aa3bSJed Brown 
17960a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
17970a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
17980a96aa3bSJed Brown         for (i = 0; i < 3; i++)   conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
17990a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
18000a96aa3bSJed Brown       }
18015f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexVecRestoreClosure(dm, coordSec, coordVec, c, &dof, &cellCoords));
18020a96aa3bSJed Brown     }
18030a96aa3bSJed Brown   }
18040a96aa3bSJed Brown 
18050a96aa3bSJed Brown #if defined(P4EST_ENABLE_DEBUG)
18062c71b3e2SJacob Faibussowitsch   PetscCheckFalse(!p4est_connectivity_is_valid(conn),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Plex to p4est conversion failed");
18070a96aa3bSJed Brown #endif
18080a96aa3bSJed Brown 
18090a96aa3bSJed Brown   *connOut = conn;
18100a96aa3bSJed Brown 
18110a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
18120a96aa3bSJed Brown 
18130a96aa3bSJed Brown   PetscFunctionReturn(0);
18140a96aa3bSJed Brown }
18150a96aa3bSJed Brown 
18160a96aa3bSJed Brown static PetscErrorCode locidx_to_PetscInt(sc_array_t * array)
18170a96aa3bSJed Brown {
18180a96aa3bSJed Brown   sc_array_t *newarray;
18190a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18200a96aa3bSJed Brown 
18210a96aa3bSJed Brown   PetscFunctionBegin;
18222c71b3e2SJacob Faibussowitsch   PetscCheckFalse(array->elem_size != sizeof(p4est_locidx_t),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
18230a96aa3bSJed Brown 
18240a96aa3bSJed Brown   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(0);
18250a96aa3bSJed Brown 
18260a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscInt), array->elem_count);
18270a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18280a96aa3bSJed Brown     p4est_locidx_t il  = *((p4est_locidx_t*) sc_array_index (array, zz));
18290a96aa3bSJed Brown     PetscInt       *ip = (PetscInt*) sc_array_index (newarray, zz);
18300a96aa3bSJed Brown 
18310a96aa3bSJed Brown     *ip = (PetscInt) il;
18320a96aa3bSJed Brown   }
18330a96aa3bSJed Brown 
18340a96aa3bSJed Brown   sc_array_reset (array);
18350a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscInt), count);
18360a96aa3bSJed Brown   sc_array_copy (array, newarray);
18370a96aa3bSJed Brown   sc_array_destroy (newarray);
18380a96aa3bSJed Brown   PetscFunctionReturn(0);
18390a96aa3bSJed Brown }
18400a96aa3bSJed Brown 
18410a96aa3bSJed Brown static PetscErrorCode coords_double_to_PetscScalar(sc_array_t * array, PetscInt dim)
18420a96aa3bSJed Brown {
18430a96aa3bSJed Brown   sc_array_t *newarray;
18440a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18450a96aa3bSJed Brown 
18460a96aa3bSJed Brown   PetscFunctionBegin;
18472c71b3e2SJacob Faibussowitsch   PetscCheckFalse(array->elem_size != 3 * sizeof(double),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong coordinate size");
18480a96aa3bSJed Brown #if !defined(PETSC_USE_COMPLEX)
18490a96aa3bSJed Brown   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(0);
18500a96aa3bSJed Brown #endif
18510a96aa3bSJed Brown 
18520a96aa3bSJed Brown   newarray = sc_array_new_size (dim * sizeof(PetscScalar), array->elem_count);
18530a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18540a96aa3bSJed Brown     int         i;
18550a96aa3bSJed Brown     double      *id = (double*) sc_array_index (array, zz);
18560a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar*) sc_array_index (newarray, zz);
18570a96aa3bSJed Brown 
18580a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
18590a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim,3); i++) ip[i] = (PetscScalar) id[i];
18600a96aa3bSJed Brown   }
18610a96aa3bSJed Brown 
18620a96aa3bSJed Brown   sc_array_reset (array);
18630a96aa3bSJed Brown   sc_array_init_size (array, dim * sizeof(PetscScalar), count);
18640a96aa3bSJed Brown   sc_array_copy (array, newarray);
18650a96aa3bSJed Brown   sc_array_destroy (newarray);
18660a96aa3bSJed Brown   PetscFunctionReturn(0);
18670a96aa3bSJed Brown }
18680a96aa3bSJed Brown 
18690a96aa3bSJed Brown static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t * array)
18700a96aa3bSJed Brown {
18710a96aa3bSJed Brown   sc_array_t *newarray;
18720a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18730a96aa3bSJed Brown 
18740a96aa3bSJed Brown   PetscFunctionBegin;
18752c71b3e2SJacob Faibussowitsch   PetscCheckFalse(array->elem_size != 2 * sizeof(p4est_locidx_t),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
18760a96aa3bSJed Brown 
18770a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscSFNode), array->elem_count);
18780a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18790a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t*) sc_array_index (array, zz);
18800a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode*) sc_array_index (newarray, zz);
18810a96aa3bSJed Brown 
18820a96aa3bSJed Brown     ip->rank  = (PetscInt) il[0];
18830a96aa3bSJed Brown     ip->index = (PetscInt) il[1];
18840a96aa3bSJed Brown   }
18850a96aa3bSJed Brown 
18860a96aa3bSJed Brown   sc_array_reset (array);
18870a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscSFNode), count);
18880a96aa3bSJed Brown   sc_array_copy (array, newarray);
18890a96aa3bSJed Brown   sc_array_destroy (newarray);
18900a96aa3bSJed Brown   PetscFunctionReturn(0);
18910a96aa3bSJed Brown }
18920a96aa3bSJed Brown 
18930a96aa3bSJed Brown static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM * plex)
18940a96aa3bSJed Brown {
18950a96aa3bSJed Brown   PetscFunctionBegin;
18960a96aa3bSJed Brown   {
18970a96aa3bSJed Brown     sc_array_t     *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
18980a96aa3bSJed Brown     sc_array_t     *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
18990a96aa3bSJed Brown     sc_array_t     *cones             = sc_array_new(sizeof(p4est_locidx_t));
19000a96aa3bSJed Brown     sc_array_t     *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
19010a96aa3bSJed Brown     sc_array_t     *coords            = sc_array_new(3 * sizeof(double));
19020a96aa3bSJed Brown     sc_array_t     *children          = sc_array_new(sizeof(p4est_locidx_t));
19030a96aa3bSJed Brown     sc_array_t     *parents           = sc_array_new(sizeof(p4est_locidx_t));
19040a96aa3bSJed Brown     sc_array_t     *childids          = sc_array_new(sizeof(p4est_locidx_t));
19050a96aa3bSJed Brown     sc_array_t     *leaves            = sc_array_new(sizeof(p4est_locidx_t));
19060a96aa3bSJed Brown     sc_array_t     *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
19070a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
19080a96aa3bSJed Brown 
19090a96aa3bSJed 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));
19100a96aa3bSJed Brown 
19115f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(points_per_dim));
19125f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(cone_sizes));
19135f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(cones));
19145f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(cone_orientations));
19155f80ce2aSJacob Faibussowitsch     CHKERRQ(coords_double_to_PetscScalar(coords, P4EST_DIM));
19160a96aa3bSJed Brown 
19175f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexCreate(PETSC_COMM_SELF,plex));
19185f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetDimension(*plex,P4EST_DIM));
19195f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexCreateFromDAG(*plex,P4EST_DIM,(PetscInt*)points_per_dim->array,(PetscInt*)cone_sizes->array,(PetscInt*)cones->array,(PetscInt*)cone_orientations->array,(PetscScalar*)coords->array));
19205f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexConvertOldOrientations_Internal(*plex));
19210a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
19220a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
19230a96aa3bSJed Brown     sc_array_destroy (cones);
19240a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
19250a96aa3bSJed Brown     sc_array_destroy (coords);
19260a96aa3bSJed Brown     sc_array_destroy (children);
19270a96aa3bSJed Brown     sc_array_destroy (parents);
19280a96aa3bSJed Brown     sc_array_destroy (childids);
19290a96aa3bSJed Brown     sc_array_destroy (leaves);
19300a96aa3bSJed Brown     sc_array_destroy (remotes);
19310a96aa3bSJed Brown   }
19320a96aa3bSJed Brown   PetscFunctionReturn(0);
19330a96aa3bSJed Brown }
19340a96aa3bSJed Brown 
19350a96aa3bSJed Brown #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
19360a96aa3bSJed Brown static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB,PetscInt *childB)
19370a96aa3bSJed Brown {
19380a96aa3bSJed Brown   PetscInt       coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
19390a96aa3bSJed Brown 
19400a96aa3bSJed Brown   PetscFunctionBegin;
19410a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
19420a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
19430a96aa3bSJed Brown     if (childB) *childB = childA;
19440a96aa3bSJed Brown     PetscFunctionReturn(0);
19450a96aa3bSJed Brown   }
19465f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd));
19470a96aa3bSJed Brown   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invarient under rotation */
19480a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
19490a96aa3bSJed Brown     if (childB) *childB = childA;
19500a96aa3bSJed Brown     PetscFunctionReturn(0);
19510a96aa3bSJed Brown   }
19520a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
19535f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd));
19540a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
19550a96aa3bSJed Brown   }
19562c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dim > 2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
1957*28b400f6SJacob Faibussowitsch   PetscCheck(dim,PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
19580a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
19590a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
19600a96aa3bSJed Brown     PetscInt       size, i, sA = -1, sB, sOrientB, sConeSize;
19610a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
19620a96aa3bSJed Brown 
19635f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSupportSize(dm,childA,&size));
19645f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetSupport(dm,childA,&supp));
19650a96aa3bSJed Brown 
19660a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
19670a96aa3bSJed Brown     for (i = 0; i < size; i++) {
19680a96aa3bSJed Brown       PetscInt sParent;
19690a96aa3bSJed Brown 
19700a96aa3bSJed Brown       sA = supp[i];
19710a96aa3bSJed Brown       if (sA == parent) continue;
19725f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTreeParent(dm,sA,&sParent,NULL));
19730a96aa3bSJed Brown       if (sParent == parent) break;
19740a96aa3bSJed Brown     }
19752c71b3e2SJacob Faibussowitsch     PetscCheckFalse(i == size,PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
19760a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
19770a96aa3bSJed Brown      * parentOrientB */
19785f80ce2aSJacob Faibussowitsch     CHKERRQ(DMReferenceTreeGetChildSymmetry_pforest(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB));
19795f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeSize(dm,sA,&sConeSize));
19805f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(dm,sA,&coneA));
19815f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCone(dm,sB,&coneB));
19825f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeOrientation(dm,sA,&oA));
19835f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetConeOrientation(dm,sB,&oB));
19840a96aa3bSJed Brown     /* step through the cone of sA in natural order */
19850a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
19860a96aa3bSJed Brown       if (coneA[i] == childA) {
19870a96aa3bSJed Brown         /* if childA is at position i in coneA,
19880a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
19890a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
19900a96aa3bSJed Brown         if (childB) *childB = coneB[j];
19910a96aa3bSJed Brown         if (childOrientB) {
19920a96aa3bSJed Brown           DMPolytopeType ct;
19930a96aa3bSJed Brown           PetscInt       oBtrue;
19940a96aa3bSJed Brown 
19955f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetConeSize(dm,childA,&coneSize));
19960a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
19972c71b3e2SJacob Faibussowitsch           PetscCheckFalse(coneSize != 0 && coneSize != 2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
19980a96aa3bSJed Brown           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
19990a96aa3bSJed Brown           /* we may have to flip an edge */
20000a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
20010a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
20020a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize,DMPolytopeConvertNewOrientation_Internal(ct, oA[i]),oBtrue);
20030a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
20040a96aa3bSJed Brown         }
20050a96aa3bSJed Brown         break;
20060a96aa3bSJed Brown       }
20070a96aa3bSJed Brown     }
20082c71b3e2SJacob Faibussowitsch     PetscCheckFalse(i == sConeSize,PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
20090a96aa3bSJed Brown     PetscFunctionReturn(0);
20100a96aa3bSJed Brown   }
20110a96aa3bSJed Brown   /* get the cone size and symmetry swap */
20125f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetConeSize(dm,parent,&coneSize));
20130a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
20140a96aa3bSJed Brown   if (dim == 2) {
20150a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
20160a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
20170a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
20180a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
20190a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
20200a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
20210a96aa3bSJed Brown   } else {
20220a96aa3bSJed Brown     oAvert     = parentOrientA;
20230a96aa3bSJed Brown     oBvert     = parentOrientB;
20240a96aa3bSJed Brown     ABswapVert = ABswap;
20250a96aa3bSJed Brown   }
20260a96aa3bSJed Brown   if (childB) {
20270a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
20280a96aa3bSJed Brown     PetscInt       p, posA = -1, numChildren, i;
20290a96aa3bSJed Brown     const PetscInt *children;
20300a96aa3bSJed Brown 
20310a96aa3bSJed Brown     /* count which position the child is in */
20325f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTreeChildren(dm,parent,&numChildren,&children));
20330a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
20340a96aa3bSJed Brown       p = children[i];
20350a96aa3bSJed Brown       if (p == childA) {
20360a96aa3bSJed Brown         if (dim == 1) {
20370a96aa3bSJed Brown           posA = i;
20380a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
20390a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
20400a96aa3bSJed Brown         }
20410a96aa3bSJed Brown         break;
20420a96aa3bSJed Brown       }
20430a96aa3bSJed Brown     }
20440a96aa3bSJed Brown     if (posA >= coneSize) {
20450a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not find childA in children of parent");
20460a96aa3bSJed Brown     } else {
20470a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
20480a96aa3bSJed Brown       PetscInt posB, childIdB;
20490a96aa3bSJed Brown 
20500a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
20510a96aa3bSJed Brown       if (dim == 1) {
20520a96aa3bSJed Brown         childIdB = posB;
20530a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
20540a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
20550a96aa3bSJed Brown       }
20560a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
20570a96aa3bSJed Brown     }
20580a96aa3bSJed Brown   }
20590a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
20600a96aa3bSJed Brown   PetscFunctionReturn(0);
20610a96aa3bSJed Brown }
20620a96aa3bSJed Brown 
20630a96aa3bSJed Brown #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
20640a96aa3bSJed Brown static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm)
20650a96aa3bSJed Brown {
20660a96aa3bSJed Brown   p4est_connectivity_t *refcube;
20670a96aa3bSJed Brown   p4est_t              *root, *refined;
20680a96aa3bSJed Brown   DM                   dmRoot, dmRefined;
20690a96aa3bSJed Brown   DM_Plex              *mesh;
20700a96aa3bSJed Brown   PetscMPIInt          rank;
20710a96aa3bSJed Brown 
20720a96aa3bSJed Brown   PetscFunctionBegin;
20730a96aa3bSJed Brown   PetscStackCallP4estReturn(refcube,p4est_connectivity_new_byname,("unit"));
20740a96aa3bSJed Brown   { /* [-1,1]^d geometry */
20750a96aa3bSJed Brown     PetscInt i, j;
20760a96aa3bSJed Brown 
20770a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
20780a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
20790a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
20800a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
20810a96aa3bSJed Brown       }
20820a96aa3bSJed Brown     }
20830a96aa3bSJed Brown   }
20840a96aa3bSJed Brown   PetscStackCallP4estReturn(root,p4est_new,(PETSC_COMM_SELF,refcube,0,NULL,NULL));
20850a96aa3bSJed Brown   PetscStackCallP4estReturn(refined,p4est_new_ext,(PETSC_COMM_SELF,refcube,0,1,1,0,NULL,NULL));
20865f80ce2aSJacob Faibussowitsch   CHKERRQ(P4estToPlex_Local(root,&dmRoot));
20875f80ce2aSJacob Faibussowitsch   CHKERRQ(P4estToPlex_Local(refined,&dmRefined));
20880a96aa3bSJed Brown   {
20890a96aa3bSJed Brown #if !defined(P4_TO_P8)
20900a96aa3bSJed Brown     PetscInt nPoints  = 25;
20910a96aa3bSJed Brown     PetscInt perm[25] = {0, 1, 2, 3,
20920a96aa3bSJed Brown                           4, 12, 8, 14,
20930a96aa3bSJed Brown                               6, 9, 15,
20940a96aa3bSJed Brown                           5, 13,    10,
20950a96aa3bSJed Brown                               7,    11,
20960a96aa3bSJed Brown                          16, 22, 20, 24,
20970a96aa3bSJed Brown                              17,     21,
20980a96aa3bSJed Brown                                  18, 23,
20990a96aa3bSJed Brown                                      19};
21000a96aa3bSJed Brown     PetscInt ident[25] = {0, 0, 0, 0,
21010a96aa3bSJed Brown                           1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0,
21020a96aa3bSJed Brown                           5, 6, 7, 8, 1, 2, 3, 4, 0};
21030a96aa3bSJed Brown #else
21040a96aa3bSJed Brown     PetscInt nPoints   = 125;
21050a96aa3bSJed Brown     PetscInt perm[125] = {0, 1, 2, 3, 4, 5, 6, 7,
21060a96aa3bSJed Brown                            8, 32, 16, 36, 24, 40,
21070a96aa3bSJed Brown                               12, 17, 37, 25, 41,
21080a96aa3bSJed Brown                            9, 33,     20, 26, 42,
21090a96aa3bSJed Brown                               13,     21, 27, 43,
21100a96aa3bSJed Brown                           10, 34, 18, 38,     28,
21110a96aa3bSJed Brown                               14, 19, 39,     29,
21120a96aa3bSJed Brown                           11, 35,     22,     30,
21130a96aa3bSJed Brown                               15,     23,     31,
21140a96aa3bSJed Brown                           44, 84, 76, 92, 52, 86, 68, 94, 60, 78, 70, 96,
21150a96aa3bSJed Brown                           45, 85, 77, 93,     54,     72,     62,     74,
21160a96aa3bSJed Brown                               46,     80, 53, 87, 69, 95,         64, 82,
21170a96aa3bSJed Brown                               47,     81,     55,     73,             66,
21180a96aa3bSJed Brown                                   48, 88,         56, 90, 61, 79, 71, 97,
21190a96aa3bSJed Brown                                   49, 89,             58,     63,     75,
21200a96aa3bSJed Brown                                       50,         57, 91,         65, 83,
21210a96aa3bSJed Brown                                       51,             59,             67,
21220a96aa3bSJed Brown                            98, 106, 110, 122, 114, 120, 118, 124,
21230a96aa3bSJed Brown                                 99,      111,      115,      119,
21240a96aa3bSJed Brown                                     100, 107,           116, 121,
21250a96aa3bSJed Brown                                          101,                117,
21260a96aa3bSJed Brown                                               102, 108, 112, 123,
21270a96aa3bSJed Brown                                                    103,      113,
21280a96aa3bSJed Brown                                                         104, 109,
21290a96aa3bSJed Brown                                                              105};
21300a96aa3bSJed Brown     PetscInt ident[125] = {0, 0, 0, 0, 0, 0, 0, 0,
21310a96aa3bSJed 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,
21320a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21330a96aa3bSJed 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,
21340a96aa3bSJed 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,
21350a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0,
21360a96aa3bSJed Brown                            19, 20, 21, 22, 23, 24, 25, 26,
21370a96aa3bSJed Brown                            7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
21380a96aa3bSJed Brown                            1, 2, 3, 4, 5, 6,
21390a96aa3bSJed Brown                            0};
21400a96aa3bSJed Brown 
21410a96aa3bSJed Brown #endif
21420a96aa3bSJed Brown     IS permIS;
21430a96aa3bSJed Brown     DM dmPerm;
21440a96aa3bSJed Brown 
21455f80ce2aSJacob Faibussowitsch     CHKERRQ(ISCreateGeneral(PETSC_COMM_SELF,nPoints,perm,PETSC_USE_POINTER,&permIS));
21465f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexPermute(dmRefined,permIS,&dmPerm));
21470a96aa3bSJed Brown     if (dmPerm) {
21485f80ce2aSJacob Faibussowitsch       CHKERRQ(DMDestroy(&dmRefined));
21490a96aa3bSJed Brown       dmRefined = dmPerm;
21500a96aa3bSJed Brown     }
21515f80ce2aSJacob Faibussowitsch     CHKERRQ(ISDestroy(&permIS));
21520a96aa3bSJed Brown     {
21530a96aa3bSJed Brown       PetscInt p;
21545f80ce2aSJacob Faibussowitsch       CHKERRQ(DMCreateLabel(dmRoot,"identity"));
21555f80ce2aSJacob Faibussowitsch       CHKERRQ(DMCreateLabel(dmRefined,"identity"));
21560a96aa3bSJed Brown       for (p = 0; p < P4EST_INSUL; p++) {
21575f80ce2aSJacob Faibussowitsch         CHKERRQ(DMSetLabelValue(dmRoot,"identity",p,p));
21580a96aa3bSJed Brown       }
21590a96aa3bSJed Brown       for (p = 0; p < nPoints; p++) {
21605f80ce2aSJacob Faibussowitsch         CHKERRQ(DMSetLabelValue(dmRefined,"identity",p,ident[p]));
21610a96aa3bSJed Brown       }
21620a96aa3bSJed Brown     }
21630a96aa3bSJed Brown   }
21645f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexCreateReferenceTree_Union(dmRoot,dmRefined,"identity",dm));
21650a96aa3bSJed Brown   mesh                   = (DM_Plex*) (*dm)->data;
21660a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
21675f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm,&rank));
21680a96aa3bSJed Brown   if (rank == 0) {
21695f80ce2aSJacob Faibussowitsch     CHKERRQ(DMViewFromOptions(dmRoot,   NULL,"-dm_p4est_ref_root_view"));
21705f80ce2aSJacob Faibussowitsch     CHKERRQ(DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_refined_view"));
21715f80ce2aSJacob Faibussowitsch     CHKERRQ(DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_tree_view"));
21720a96aa3bSJed Brown   }
21735f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&dmRefined));
21745f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&dmRoot));
21750a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(refined));
21760a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(root));
21770a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,(refcube));
21780a96aa3bSJed Brown   PetscFunctionReturn(0);
21790a96aa3bSJed Brown }
21800a96aa3bSJed Brown 
21810a96aa3bSJed Brown static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB)
21820a96aa3bSJed Brown {
21830a96aa3bSJed Brown   void          *ctx;
21840a96aa3bSJed Brown   PetscInt       num;
21850a96aa3bSJed Brown   PetscReal      val;
21860a96aa3bSJed Brown 
21870a96aa3bSJed Brown   PetscFunctionBegin;
21885f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetApplicationContext(dmA,&ctx));
21895f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetApplicationContext(dmB,ctx));
21905f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCopyDisc(dmA,dmB));
21915f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetOutputSequenceNumber(dmA,&num,&val));
21925f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetOutputSequenceNumber(dmB,num,val));
21930a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
21945f80ce2aSJacob Faibussowitsch     CHKERRQ(DMClearLocalVectors(dmB));
21955f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)dmA->localSection));
21965f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&(dmB->localSection)));
21970a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
21985f80ce2aSJacob Faibussowitsch     CHKERRQ(DMClearGlobalVectors(dmB));
21995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)dmA->globalSection));
22005f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&(dmB->globalSection)));
22010a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
22025f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)dmA->defaultConstraint.section));
22035f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&(dmB->defaultConstraint.section)));
22043b8ba7d1SJed Brown     dmB->defaultConstraint.section = dmA->defaultConstraint.section;
22055f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)dmA->defaultConstraint.mat));
22065f80ce2aSJacob Faibussowitsch     CHKERRQ(MatDestroy(&(dmB->defaultConstraint.mat)));
22073b8ba7d1SJed Brown     dmB->defaultConstraint.mat = dmA->defaultConstraint.mat;
22085f80ce2aSJacob Faibussowitsch     if (dmA->map) CHKERRQ(PetscLayoutReference(dmA->map, &dmB->map));
22090a96aa3bSJed Brown   }
22100a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
22115f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)dmA->sectionSF));
22125f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&dmB->sectionSF));
22130a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
22140a96aa3bSJed Brown   }
22150a96aa3bSJed Brown   PetscFunctionReturn(0);
22160a96aa3bSJed Brown }
22170a96aa3bSJed Brown 
22180a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
22190a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm,p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF)
22200a96aa3bSJed Brown {
22210a96aa3bSJed Brown   PetscInt       startF, endF, startC, endC, p, nLeaves;
22220a96aa3bSJed Brown   PetscSFNode    *leaves;
22230a96aa3bSJed Brown   PetscSF        sf;
22240a96aa3bSJed Brown   PetscInt       *recv, *send;
22250a96aa3bSJed Brown   PetscMPIInt    tag;
22260a96aa3bSJed Brown   MPI_Request    *recvReqs, *sendReqs;
22270a96aa3bSJed Brown   PetscSection   section;
22280a96aa3bSJed Brown 
22290a96aa3bSJed Brown   PetscFunctionBegin;
22305f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estF,p4estC,&startC,&endC));
22315f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(2*(endC-startC),&recv,endC-startC,&recvReqs));
22325f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCommGetNewTag(comm,&tag));
22330a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22340a96aa3bSJed Brown     recvReqs[p-startC] = MPI_REQUEST_NULL; /* just in case we don't initiate a receive */
22350a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p+1]) { /* empty coarse partition */
22360a96aa3bSJed Brown       recv[2*(p-startC)]   = 0;
22370a96aa3bSJed Brown       recv[2*(p-startC)+1] = 0;
22380a96aa3bSJed Brown       continue;
22390a96aa3bSJed Brown     }
22400a96aa3bSJed Brown 
22415f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Irecv(&recv[2*(p-startC)],2,MPIU_INT,p,tag,comm,&recvReqs[p-startC]));
22420a96aa3bSJed Brown   }
22435f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estC,p4estF,&startF,&endF));
22445f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(2*(endF-startF),&send,endF-startF,&sendReqs));
22450a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
22460a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
22470a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
22480a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p+1];
22490a96aa3bSJed Brown     PetscInt         tStart       = (PetscInt) myFineStart->p.which_tree;
22500a96aa3bSJed Brown     PetscInt         tEnd         = (PetscInt) myFineEnd->p.which_tree;
22510a96aa3bSJed Brown     PetscInt         firstCell    = -1, lastCell = -1;
22520a96aa3bSJed Brown     p4est_tree_t     *treeStart   = &(((p4est_tree_t*) p4estC->trees->array)[tStart]);
22530a96aa3bSJed Brown     p4est_tree_t     *treeEnd     = (size_t) tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t*) p4estC->trees->array)[tEnd]) : NULL;
22540a96aa3bSJed Brown     ssize_t          overlapIndex;
22550a96aa3bSJed Brown 
22560a96aa3bSJed Brown     sendReqs[p-startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
22570a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p+1]) continue;
22580a96aa3bSJed Brown 
22590a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
22600a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
22610a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeStart->quadrants),myFineStart,p4est_quadrant_disjoint));
22620a96aa3bSJed Brown       if (overlapIndex < 0) {
22630a96aa3bSJed Brown         firstCell = 0;
22640a96aa3bSJed Brown       } else {
22650a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
22660a96aa3bSJed Brown       }
22670a96aa3bSJed Brown     } else {
22680a96aa3bSJed Brown       firstCell = 0;
22690a96aa3bSJed Brown     }
22700a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
22710a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeEnd->quadrants),myFineEnd,p4est_quadrant_disjoint));
22720a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
22730a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
22740a96aa3bSJed Brown       } else {
22750a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t*) treeEnd->quadrants.array)[overlapIndex]);
22760a96aa3bSJed Brown         p4est_quadrant_t first_desc;
22770a96aa3bSJed Brown         int              equal;
22780a96aa3bSJed Brown 
22790a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_first_descendant,(container,&first_desc,P4EST_QMAXLEVEL));
22800a96aa3bSJed Brown         PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(myFineEnd,&first_desc));
22810a96aa3bSJed Brown         if (equal) {
22820a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
22830a96aa3bSJed Brown         } else {
22840a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
22850a96aa3bSJed Brown         }
22860a96aa3bSJed Brown       }
22870a96aa3bSJed Brown     } else {
22880a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
22890a96aa3bSJed Brown     }
22900a96aa3bSJed Brown     send[2*(p-startF)]   = firstCell;
22910a96aa3bSJed Brown     send[2*(p-startF)+1] = lastCell - firstCell;
22925f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Isend(&send[2*(p-startF)],2,MPIU_INT,p,tag,comm,&sendReqs[p-startF]));
22930a96aa3bSJed Brown   }
22945f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Waitall((PetscMPIInt)(endC-startC),recvReqs,MPI_STATUSES_IGNORE));
22955f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF,&section));
22965f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(section,startC,endC));
22970a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22980a96aa3bSJed Brown     PetscInt numCells = recv[2*(p-startC)+1];
22995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(section,p,numCells));
23000a96aa3bSJed Brown   }
23015f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(section));
23025f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(section,&nLeaves));
23035f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(nLeaves,&leaves));
23040a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
23050a96aa3bSJed Brown     PetscInt firstCell = recv[2*(p-startC)];
23060a96aa3bSJed Brown     PetscInt numCells  = recv[2*(p-startC)+1];
23070a96aa3bSJed Brown     PetscInt off, i;
23080a96aa3bSJed Brown 
23095f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(section,p,&off));
23100a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
23110a96aa3bSJed Brown       leaves[off+i].rank  = p;
23120a96aa3bSJed Brown       leaves[off+i].index = firstCell + i;
23130a96aa3bSJed Brown     }
23140a96aa3bSJed Brown   }
23155f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFCreate(comm,&sf));
23165f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFSetGraph(sf,cEnd-cStart,nLeaves,NULL,PETSC_OWN_POINTER,leaves,PETSC_OWN_POINTER));
23175f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&section));
23185f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Waitall((PetscMPIInt)(endF-startF),sendReqs,MPI_STATUSES_IGNORE));
23195f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(send,sendReqs));
23205f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(recv,recvReqs));
23210a96aa3bSJed Brown   *coveringSF = sf;
23220a96aa3bSJed Brown   PetscFunctionReturn(0);
23230a96aa3bSJed Brown }
23240a96aa3bSJed Brown 
23250a96aa3bSJed Brown /* closure points for locally-owned cells */
23260a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints,PetscBool redirect)
23270a96aa3bSJed Brown {
23280a96aa3bSJed Brown   PetscInt          cStart, cEnd;
23290a96aa3bSJed Brown   PetscInt          count, c;
23300a96aa3bSJed Brown   PetscMPIInt       rank;
23310a96aa3bSJed Brown   PetscInt          closureSize = -1;
23320a96aa3bSJed Brown   PetscInt          *closure    = NULL;
23330a96aa3bSJed Brown   PetscSF           pointSF;
23340a96aa3bSJed Brown   PetscInt          nleaves, nroots;
23350a96aa3bSJed Brown   const PetscInt    *ilocal;
23360a96aa3bSJed Brown   const PetscSFNode *iremote;
23370a96aa3bSJed Brown   DM                plex;
23380a96aa3bSJed Brown   DM_Forest         *forest;
23390a96aa3bSJed Brown   DM_Forest_pforest *pforest;
23400a96aa3bSJed Brown 
23410a96aa3bSJed Brown   PetscFunctionBegin;
23420a96aa3bSJed Brown   forest            = (DM_Forest *) dm->data;
23430a96aa3bSJed Brown   pforest           = (DM_Forest_pforest *) forest->data;
23440a96aa3bSJed Brown   cStart            = pforest->cLocalStart;
23450a96aa3bSJed Brown   cEnd              = pforest->cLocalEnd;
23465f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
23475f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPointSF(dm,&pointSF));
23485f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFGetGraph(pointSF,&nroots,&nleaves,&ilocal,&iremote));
23490a96aa3bSJed Brown   nleaves           = PetscMax(0,nleaves);
23500a96aa3bSJed Brown   nroots            = PetscMax(0,nroots);
23510a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
23525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(*numClosurePoints,closurePoints));
23535f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
23540a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
23550a96aa3bSJed Brown     PetscInt i;
23565f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure));
23570a96aa3bSJed Brown 
23580a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
23590a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
23600a96aa3bSJed Brown       PetscInt loc = -1;
23610a96aa3bSJed Brown 
23625f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFindInt(p,nleaves,ilocal,&loc));
23630a96aa3bSJed Brown       if (redirect && loc >= 0) {
23640a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
23650a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
23660a96aa3bSJed Brown       } else {
23670a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
23680a96aa3bSJed Brown         (*closurePoints)[count].index = p;
23690a96aa3bSJed Brown       }
23700a96aa3bSJed Brown     }
23715f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexRestoreTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure));
23720a96aa3bSJed Brown   }
23730a96aa3bSJed Brown   PetscFunctionReturn(0);
23740a96aa3bSJed Brown }
23750a96aa3bSJed Brown 
23760a96aa3bSJed Brown static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type)
23770a96aa3bSJed Brown {
23780a96aa3bSJed Brown   PetscMPIInt i;
23790a96aa3bSJed Brown 
23800a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
23810a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode*)a;
23820a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode*)b;
23830a96aa3bSJed Brown 
23840a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
23850a96aa3bSJed Brown   }
23860a96aa3bSJed Brown }
23870a96aa3bSJed Brown 
23880a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
23890a96aa3bSJed Brown {
23900a96aa3bSJed Brown   MPI_Comm          comm;
23910a96aa3bSJed Brown   PetscMPIInt       rank, size;
23920a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
23930a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
23940a96aa3bSJed Brown   PetscInt          numClosureIndices;
23950a96aa3bSJed Brown   PetscInt          numClosurePointsC, numClosurePointsF;
23960a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
23970a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
23980a96aa3bSJed Brown   p4est_quadrant_t  **treeQuads;
23990a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
24000a96aa3bSJed Brown   MPI_Datatype      nodeType;
24010a96aa3bSJed Brown   MPI_Datatype      nodeClosureType;
24020a96aa3bSJed Brown   MPI_Op            sfNodeReduce;
24030a96aa3bSJed Brown   p4est_topidx_t    fltF, lltF, t;
24040a96aa3bSJed Brown   DM                plexC, plexF;
24050a96aa3bSJed Brown   PetscInt          pStartF, pEndF, pStartC, pEndC;
24060a96aa3bSJed Brown   PetscBool         saveInCoarse = PETSC_FALSE;
24070a96aa3bSJed Brown   PetscBool         saveInFine   = PETSC_FALSE;
24080a96aa3bSJed Brown   PetscBool         formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
24090a96aa3bSJed Brown   PetscInt          *cids        = NULL;
24100a96aa3bSJed Brown 
24110a96aa3bSJed Brown   PetscFunctionBegin;
24120a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
24130a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
24140a96aa3bSJed Brown   p4estC   = pforestC->forest;
24150a96aa3bSJed Brown   p4estF   = pforestF->forest;
24162c71b3e2SJacob Faibussowitsch   PetscCheckFalse(pforestC->topo != pforestF->topo,PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
24170a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
24185f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm,&rank));
24195f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_size(comm,&size));
24205f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(fine,&plexF));
24215f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(plexF,&pStartF,&pEndF));
24225f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(coarse,&plexC));
24235f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(plexC,&pStartC,&pEndC));
24240a96aa3bSJed Brown   { /* check if the results have been cached */
24250a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
24260a96aa3bSJed Brown 
24275f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetAdaptivityForest(coarse,&adaptCoarse));
24285f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetAdaptivityForest(fine,&adaptFine));
24290a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
24300a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
24315f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscObjectReference((PetscObject)(pforestC->pointSelfToAdaptSF)));
24320a96aa3bSJed Brown         *sf  = pforestC->pointSelfToAdaptSF;
24330a96aa3bSJed Brown         if (childIds) {
24345f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1(pEndF-pStartF,&cids));
24355f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscArraycpy(cids,pforestC->pointSelfToAdaptCids,pEndF-pStartF));
24360a96aa3bSJed Brown           *childIds = cids;
24370a96aa3bSJed Brown         }
24380a96aa3bSJed Brown         PetscFunctionReturn(0);
24390a96aa3bSJed Brown       } else {
24400a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
24410a96aa3bSJed Brown         formCids     = PETSC_TRUE;
24420a96aa3bSJed Brown       }
24430a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
24440a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
24455f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscObjectReference((PetscObject)(pforestF->pointAdaptToSelfSF)));
24460a96aa3bSJed Brown         *sf  = pforestF->pointAdaptToSelfSF;
24470a96aa3bSJed Brown         if (childIds) {
24485f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscMalloc1(pEndF-pStartF,&cids));
24495f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscArraycpy(cids,pforestF->pointAdaptToSelfCids,pEndF-pStartF));
24500a96aa3bSJed Brown           *childIds = cids;
24510a96aa3bSJed Brown         }
24520a96aa3bSJed Brown         PetscFunctionReturn(0);
24530a96aa3bSJed Brown       } else {
24540a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
24550a96aa3bSJed Brown         formCids   = PETSC_TRUE;
24560a96aa3bSJed Brown       }
24570a96aa3bSJed Brown     }
24580a96aa3bSJed Brown   }
24590a96aa3bSJed Brown 
24600a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
24610a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
24620a96aa3bSJed Brown   /* create the datatype */
24635f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Type_contiguous(2,MPIU_INT,&nodeType));
24645f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Type_commit(&nodeType));
24655f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Op_create(DMPforestMaxSFNode,PETSC_FALSE,&sfNodeReduce));
24665f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Type_contiguous(numClosureIndices*2,MPIU_INT,&nodeClosureType));
24675f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Type_commit(&nodeClosureType));
24680a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
24690a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
24705f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetCellSFNodes(coarse,numClosureIndices,&numClosurePointsC,&closurePointsC,PETSC_TRUE));
24715f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetCellSFNodes(fine  ,numClosureIndices,&numClosurePointsF,&closurePointsF,PETSC_FALSE));
24720a96aa3bSJed Brown   /* create pointers for tree lists */
24730a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
24740a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
24755f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc2(lltF + 1  - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts));
24760a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
24770a96aa3bSJed Brown   if (size > 1) {
24780a96aa3bSJed Brown     PetscInt p;
24790a96aa3bSJed Brown 
24800a96aa3bSJed Brown     for (p = 0; p < size; p++) {
24810a96aa3bSJed Brown       int equal;
24820a96aa3bSJed Brown 
24830a96aa3bSJed Brown       PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal_piggy,(&p4estC->global_first_position[p],&p4estF->global_first_position[p]));
24840a96aa3bSJed Brown       if (!equal) break;
24850a96aa3bSJed Brown     }
24860a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
24870a96aa3bSJed Brown       PetscInt         cStartC, cEndC;
24880a96aa3bSJed Brown       PetscSF          coveringSF;
24890a96aa3bSJed Brown       PetscInt         nleaves;
24900a96aa3bSJed Brown       PetscInt         count;
24910a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
24920a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
24930a96aa3bSJed Brown       p4est_topidx_t   fltC = p4estC->first_local_tree;
24940a96aa3bSJed Brown       p4est_topidx_t   lltC = p4estC->last_local_tree;
24950a96aa3bSJed Brown       p4est_topidx_t   t;
24960a96aa3bSJed Brown       PetscMPIInt      blockSizes[4]   = {P4EST_DIM,2,1,1};
24970a96aa3bSJed Brown       MPI_Aint         blockOffsets[4] = {offsetof(p4est_quadrant_t,x),
24980a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,level),
24990a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,pad16),
25000a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,p)};
25010a96aa3bSJed Brown       MPI_Datatype     blockTypes[4] = {MPI_INT32_T,MPI_INT8_T,MPI_INT16_T,MPI_INT32_T/* p.which_tree */};
25020a96aa3bSJed Brown       MPI_Datatype     quadStruct,quadType;
25030a96aa3bSJed Brown 
25045f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSimplexOrBoxCells(plexC,0,&cStartC,&cEndC));
25055f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetCellCoveringSF(comm,p4estC,p4estF,pforestC->cLocalStart,pforestC->cLocalEnd,&coveringSF));
25065f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFGetGraph(coveringSF,NULL,&nleaves,NULL,NULL));
25075f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(numClosureIndices*nleaves,&newClosurePointsC));
25085f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(nleaves,&coverQuads));
25095f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(cEndC-cStartC,&coverQuadsSend));
25100a96aa3bSJed Brown       count = 0;
25110a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
25120a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
25130a96aa3bSJed Brown         PetscInt     q;
25140a96aa3bSJed Brown 
25155f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscMemcpy(&coverQuadsSend[count],tree->quadrants.array,tree->quadrants.elem_count * sizeof(p4est_quadrant_t)));
25160a96aa3bSJed Brown         for (q = 0; (size_t) q < tree->quadrants.elem_count; q++) coverQuadsSend[count+q].p.which_tree = t;
25170a96aa3bSJed Brown         count += tree->quadrants.elem_count;
25180a96aa3bSJed Brown       }
25190a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
25200a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
25210a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
25220a96aa3bSJed Brown        */
25235f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Type_create_struct(4,blockSizes,blockOffsets,blockTypes,&quadStruct));
25245f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Type_create_resized(quadStruct,0,sizeof(p4est_quadrant_t),&quadType));
25255f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Type_commit(&quadType));
25265f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE));
25275f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE));
25285f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE));
25295f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE));
25305f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Type_free(&quadStruct));
25315f80ce2aSJacob Faibussowitsch       CHKERRMPI(MPI_Type_free(&quadType));
25325f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(coverQuadsSend));
25335f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(closurePointsC));
25345f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFDestroy(&coveringSF));
25350a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
25360a96aa3bSJed Brown 
25370a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
25380a96aa3bSJed Brown       {
25390a96aa3bSJed Brown         PetscInt q;
25400a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
25410a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
25420a96aa3bSJed Brown           if (!treeQuadCounts[t-fltF]++) treeQuads[t-fltF] = &coverQuads[q];
25430a96aa3bSJed Brown         }
25440a96aa3bSJed Brown       }
25450a96aa3bSJed Brown     }
25460a96aa3bSJed Brown   }
25470a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
25480a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
25490a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
25500a96aa3bSJed Brown 
25510a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
25520a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t*) tree->quadrants.array;
25530a96aa3bSJed Brown     }
25540a96aa3bSJed Brown   }
25550a96aa3bSJed Brown 
25560a96aa3bSJed Brown   {
25570a96aa3bSJed Brown     PetscInt    p;
25580a96aa3bSJed Brown     PetscInt    cLocalStartF;
25590a96aa3bSJed Brown     PetscSF     pointSF;
25600a96aa3bSJed Brown     PetscSFNode *roots;
25610a96aa3bSJed Brown     PetscInt    *rootType;
25620a96aa3bSJed Brown     DM          refTree = NULL;
25630a96aa3bSJed Brown     DMLabel     canonical;
25640a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
25650a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
25660a96aa3bSJed Brown     PetscInt    coarseOffset;
25670a96aa3bSJed Brown     PetscInt    numCoarseQuads;
25680a96aa3bSJed Brown 
25695f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(pEndF-pStartF,&roots));
25705f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(pEndF-pStartF,&rootType));
25715f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetPointSF(fine,&pointSF));
25720a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
25730a96aa3bSJed Brown       roots[p-pStartF].rank  = -1;
25740a96aa3bSJed Brown       roots[p-pStartF].index = -1;
25750a96aa3bSJed Brown       rootType[p-pStartF]    = -1;
25760a96aa3bSJed Brown     }
25770a96aa3bSJed Brown     if (formCids) {
25780a96aa3bSJed Brown       PetscInt child;
25790a96aa3bSJed Brown 
25805f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(pEndF-pStartF,&cids));
25810a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
25825f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetReferenceTree(plexF,&refTree));
25835f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure));
25840a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
25855f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]));
25860a96aa3bSJed Brown       }
25875f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetLabel(refTree,"canonical",&canonical));
25880a96aa3bSJed Brown     }
25890a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
25900a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
25910a96aa3bSJed Brown       p4est_tree_t     *tree        = &(((p4est_tree_t*) p4estF->trees->array)[t]);
25920a96aa3bSJed Brown       PetscInt         numFineQuads = tree->quadrants.elem_count;
25930a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads = treeQuads[t - fltF];
25940a96aa3bSJed Brown       p4est_quadrant_t *fineQuads   = (p4est_quadrant_t*) tree->quadrants.array;
25950a96aa3bSJed Brown       PetscInt         i, coarseCount = 0;
25960a96aa3bSJed Brown       PetscInt         offset = tree->quadrants_offset;
25970a96aa3bSJed Brown       sc_array_t       coarseQuadsArray;
25980a96aa3bSJed Brown 
25990a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
26000a96aa3bSJed Brown       PetscStackCallP4est(sc_array_init_data,(&coarseQuadsArray,coarseQuads,sizeof(p4est_quadrant_t),(size_t) numCoarseQuads));
26010a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
26020a96aa3bSJed Brown         PetscInt         c     = i + offset;
26030a96aa3bSJed Brown         p4est_quadrant_t *quad = &fineQuads[i];
26040a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
26050a96aa3bSJed Brown         ssize_t          disjoint = -1;
26060a96aa3bSJed Brown 
26070a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
26080a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
26090a96aa3bSJed Brown           PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
26100a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
26110a96aa3bSJed Brown         }
26122c71b3e2SJacob Faibussowitsch         PetscCheckFalse(disjoint != 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"did not find overlapping coarse quad");
26130a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
26140a96aa3bSJed Brown           if (transferIdent) { /* find corners */
26150a96aa3bSJed Brown             PetscInt j = 0;
26160a96aa3bSJed Brown 
26170a96aa3bSJed Brown             do {
26180a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
26190a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
26200a96aa3bSJed Brown                 int              equal;
26210a96aa3bSJed Brown 
26220a96aa3bSJed Brown                 PetscStackCallP4est(p4est_quadrant_corner_descendant,(quad,&cornerQuad,j,quadCoarse->level));
26230a96aa3bSJed Brown                 PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(&cornerQuad,quadCoarse));
26240a96aa3bSJed Brown                 if (equal) {
26250a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
26260a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
26270a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
26280a96aa3bSJed Brown 
26290a96aa3bSJed Brown                   roots[p-pStartF]    = q;
26300a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
26310a96aa3bSJed Brown                   cids[p-pStartF]     = -1;
26320a96aa3bSJed Brown                   j++;
26330a96aa3bSJed Brown                 }
26340a96aa3bSJed Brown               }
26350a96aa3bSJed Brown               coarseCount++;
26360a96aa3bSJed Brown               disjoint = 1;
26370a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
26380a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
26390a96aa3bSJed Brown                 PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
26400a96aa3bSJed Brown               }
26410a96aa3bSJed Brown             } while (!disjoint);
26420a96aa3bSJed Brown           }
26430a96aa3bSJed Brown           continue;
26440a96aa3bSJed Brown         }
26450a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
26460a96aa3bSJed Brown           PetscInt j;
26470a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
26480a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
26490a96aa3bSJed Brown 
26500a96aa3bSJed Brown             roots[p-pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
26510a96aa3bSJed Brown             rootType[p-pStartF] = PETSC_MAX_INT; /* unconditionally accept */
26520a96aa3bSJed Brown             cids[p-pStartF]     = -1;
26530a96aa3bSJed Brown           }
26540a96aa3bSJed Brown         } else {
26550a96aa3bSJed Brown           PetscInt levelDiff = quad->level - quadCoarse->level;
26560a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
26570a96aa3bSJed Brown 
26580a96aa3bSJed Brown           if (formCids) {
26590a96aa3bSJed Brown             PetscInt cl;
26600a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
26610a96aa3bSJed Brown             int      cid;
26620a96aa3bSJed Brown 
26632c71b3e2SJacob Faibussowitsch             PetscCheckFalse(levelDiff > 1,PETSC_COMM_SELF,PETSC_ERR_USER,"Recursive child ids not implemented");
26640a96aa3bSJed Brown             PetscStackCallP4estReturn(cid,p4est_quadrant_child_id,(quad));
26655f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure));
26660a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
26670a96aa3bSJed Brown               PetscInt p      = pointClosure[2 * cl];
26680a96aa3bSJed Brown               PetscInt point  = childClosures[cid][2 * cl];
26690a96aa3bSJed Brown               PetscInt ornt   = childClosures[cid][2 * cl + 1];
26700a96aa3bSJed Brown               PetscInt newcid = -1;
26710a96aa3bSJed Brown               DMPolytopeType ct;
26720a96aa3bSJed Brown 
26730a96aa3bSJed Brown               if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
26745f80ce2aSJacob Faibussowitsch               CHKERRQ(DMPlexGetCellType(refTree, point, &ct));
26750a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
26760a96aa3bSJed Brown               if (!cl) {
26770a96aa3bSJed Brown                 newcid = cid + 1;
26780a96aa3bSJed Brown               } else {
26790a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
26800a96aa3bSJed Brown 
26815f80ce2aSJacob Faibussowitsch                 CHKERRQ(DMPlexGetTreeParent(refTree,point,&parent,NULL));
26820a96aa3bSJed Brown                 if (parent == point) {
26830a96aa3bSJed Brown                   newcid = -1;
26840a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
26850a96aa3bSJed Brown                   newcid = point;
26860a96aa3bSJed Brown                 } else {
26870a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
26880a96aa3bSJed Brown 
26890a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
26900a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
26915f80ce2aSJacob Faibussowitsch                       CHKERRQ(DMPlexGetCellType(refTree, parent, &rct));
26920a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
26930a96aa3bSJed Brown                       break;
26940a96aa3bSJed Brown                     }
26950a96aa3bSJed Brown                   }
26962c71b3e2SJacob Faibussowitsch                   PetscCheckFalse(rcl >= P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Couldn't find parent in root closure");
26975f80ce2aSJacob Faibussowitsch                   CHKERRQ(DMPlexReferenceTreeGetChildSymmetry(refTree,parent,parentOrnt,ornt,point,DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]),NULL,&newcid));
26980a96aa3bSJed Brown                 }
26990a96aa3bSJed Brown               }
27000a96aa3bSJed Brown               if (newcid >= 0) {
27010a96aa3bSJed Brown 
27020a96aa3bSJed Brown                 if (canonical) {
27035f80ce2aSJacob Faibussowitsch                   CHKERRQ(DMLabelGetValue(canonical,newcid,&newcid));
27040a96aa3bSJed Brown                 }
27050a96aa3bSJed Brown                 proposedCids[cl] = newcid;
27060a96aa3bSJed Brown               }
27070a96aa3bSJed Brown             }
27085f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexRestoreTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure));
27090a96aa3bSJed Brown           }
27100a96aa3bSJed Brown           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {{quadCoarse->x,quadCoarse->y,
27110a96aa3bSJed Brown #if defined(P4_TO_P8)
27120a96aa3bSJed Brown                                                        quadCoarse->z
27130a96aa3bSJed Brown #endif
27140a96aa3bSJed Brown                                                       },{0}};
27150a96aa3bSJed Brown           p4est_qcoord_t fineBound[2][P4EST_DIM] = {{quad->x,quad->y,
27160a96aa3bSJed Brown #if defined(P4_TO_P8)
27170a96aa3bSJed Brown                                                      quad->z
27180a96aa3bSJed Brown #endif
27190a96aa3bSJed Brown                                                     },{0}};
27200a96aa3bSJed Brown           PetscInt       j;
27210a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
27220a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
27230a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j]   + P4EST_QUADRANT_LEN(quad->level);
27240a96aa3bSJed Brown           }
27250a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
27260a96aa3bSJed Brown             PetscInt    l, p;
27270a96aa3bSJed Brown             PetscSFNode q;
27280a96aa3bSJed Brown 
27290a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
27300a96aa3bSJed Brown             if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
27310a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
27320a96aa3bSJed Brown               l = 0;
27330a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
27340a96aa3bSJed Brown               PetscInt face = PetscFaceToP4estFace[j - 1];
27350a96aa3bSJed Brown               PetscInt direction = face / 2;
27360a96aa3bSJed Brown               PetscInt coarseFace = -1;
27370a96aa3bSJed Brown 
27380a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
27390a96aa3bSJed Brown                 coarseFace = face;
27400a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27410a96aa3bSJed Brown               } else {
27420a96aa3bSJed Brown                 l = 0;
27430a96aa3bSJed Brown               }
27440a96aa3bSJed Brown #if defined(P4_TO_P8)
27450a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
27460a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
27470a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
27480a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
27490a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
27500a96aa3bSJed Brown               PetscInt  minDir     = PetscMin((direction + 1) % 3,(direction + 2) % 3);
27510a96aa3bSJed Brown               PetscInt  maxDir     = PetscMax((direction + 1) % 3,(direction + 2) % 3);
27520a96aa3bSJed Brown               PetscBool dirTest[2];
27530a96aa3bSJed Brown 
27540a96aa3bSJed Brown               dirTest[0] = (PetscBool) (coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
27550a96aa3bSJed Brown               dirTest[1] = (PetscBool) (coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
27560a96aa3bSJed Brown 
27570a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
27580a96aa3bSJed Brown                 coarseEdge = edge;
27590a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27600a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
27610a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
27620a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27630a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
27640a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
27650a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27660a96aa3bSJed Brown               } else {
27670a96aa3bSJed Brown                 l = 0;
27680a96aa3bSJed Brown               }
27690a96aa3bSJed Brown #endif
27700a96aa3bSJed Brown             } else {
27710a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
27720a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
27730a96aa3bSJed Brown               PetscInt  m;
27740a96aa3bSJed Brown               PetscInt  numMatch     = 0;
27750a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
27760a96aa3bSJed Brown #if defined(P4_TO_P8)
27770a96aa3bSJed Brown               PetscInt coarseEdge = -1;
27780a96aa3bSJed Brown #endif
27790a96aa3bSJed Brown 
27800a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
27810a96aa3bSJed Brown                 dirTest[m] = (PetscBool) (coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
27820a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
27830a96aa3bSJed Brown               }
27840a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
27850a96aa3bSJed Brown                 coarseVertex = vertex;
27860a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
27870a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
27880a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27890a96aa3bSJed Brown                   if (dirTest[m]) {
27900a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
27910a96aa3bSJed Brown                     break;
27920a96aa3bSJed Brown                   }
27930a96aa3bSJed Brown                 }
27940a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27950a96aa3bSJed Brown #if defined(P4_TO_P8)
27960a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
27970a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27980a96aa3bSJed Brown                   if (!dirTest[m]) {
27990a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
28000a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
28010a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1,otherDir2);
28020a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1,otherDir2);
28030a96aa3bSJed Brown 
28040a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
28050a96aa3bSJed Brown                     break;
28060a96aa3bSJed Brown                   }
28070a96aa3bSJed Brown                 }
28080a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
28090a96aa3bSJed Brown #endif
28100a96aa3bSJed Brown               } else { /* volume */
28110a96aa3bSJed Brown                 l = 0;
28120a96aa3bSJed Brown               }
28130a96aa3bSJed Brown             }
28140a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
28150a96aa3bSJed Brown             if (l > rootType[p-pStartF]) {
28160a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
28170a96aa3bSJed Brown                 if (transferIdent) {
28180a96aa3bSJed Brown                   roots[p-pStartF] = q;
28190a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
28200a96aa3bSJed Brown                   if (formCids) cids[p-pStartF] = -1;
28210a96aa3bSJed Brown                 }
28220a96aa3bSJed Brown               } else {
28230a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
28240a96aa3bSJed Brown 
28250a96aa3bSJed Brown                 roots[p-pStartF] = q;
28260a96aa3bSJed Brown                 rootType[p-pStartF] = l;
28270a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
28280a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
28290a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
28300a96aa3bSJed Brown                   PetscInt parent;
28310a96aa3bSJed Brown 
28325f80ce2aSJacob Faibussowitsch                   CHKERRQ(DMPlexGetTreeParent(plexF,thisp,&parent,NULL));
28330a96aa3bSJed Brown                   if (parent == thisp) break;
28340a96aa3bSJed Brown 
28350a96aa3bSJed Brown                   roots[parent-pStartF] = q;
28360a96aa3bSJed Brown                   rootType[parent-pStartF] = PETSC_MAX_INT;
28370a96aa3bSJed Brown                   if (formCids) cids[parent-pStartF] = -1;
28380a96aa3bSJed Brown                   thisp = parent;
28390a96aa3bSJed Brown                 }
28400a96aa3bSJed Brown               }
28410a96aa3bSJed Brown             }
28420a96aa3bSJed Brown           }
28430a96aa3bSJed Brown         }
28440a96aa3bSJed Brown       }
28450a96aa3bSJed Brown     }
28460a96aa3bSJed Brown 
28470a96aa3bSJed 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 */
28480a96aa3bSJed Brown     if (size > 1) {
28490a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
28500a96aa3bSJed Brown 
28515f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(pEndF-pStartF,&rootTypeCopy));
28525f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscArraycpy(rootTypeCopy,rootType,pEndF-pStartF));
28535f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX));
28545f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX));
28555f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE));
28565f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE));
28570a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28580a96aa3bSJed 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 */
28590a96aa3bSJed Brown           roots[p-pStartF].rank  = -1;
28600a96aa3bSJed Brown           roots[p-pStartF].index = -1;
28610a96aa3bSJed Brown         }
28620a96aa3bSJed Brown         if (formCids && rootTypeCopy[p-pStartF] == PETSC_MAX_INT) {
28630a96aa3bSJed Brown           cids[p-pStartF] = -1; /* we have found an antecedent that is the same: no child id */
28640a96aa3bSJed Brown         }
28650a96aa3bSJed Brown       }
28665f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(rootTypeCopy));
28675f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceBegin(pointSF,nodeType,roots,roots,sfNodeReduce));
28685f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceEnd(pointSF,nodeType,roots,roots,sfNodeReduce));
28695f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(pointSF,nodeType,roots,roots,MPI_REPLACE));
28705f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(pointSF,nodeType,roots,roots,MPI_REPLACE));
28710a96aa3bSJed Brown     }
28725f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(rootType));
28730a96aa3bSJed Brown 
28740a96aa3bSJed Brown     {
28750a96aa3bSJed Brown       PetscInt    numRoots;
28760a96aa3bSJed Brown       PetscInt    numLeaves;
28770a96aa3bSJed Brown       PetscInt    *leaves;
28780a96aa3bSJed Brown       PetscSFNode *iremote;
28790a96aa3bSJed Brown       /* count leaves */
28800a96aa3bSJed Brown 
28810a96aa3bSJed Brown       numRoots = pEndC - pStartC;
28820a96aa3bSJed Brown 
28830a96aa3bSJed Brown       numLeaves = 0;
28840a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28850a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) numLeaves++;
28860a96aa3bSJed Brown       }
28875f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(numLeaves,&leaves));
28885f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(numLeaves,&iremote));
28890a96aa3bSJed Brown       numLeaves = 0;
28900a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28910a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) {
28920a96aa3bSJed Brown           leaves[numLeaves]  = p-pStartF;
28930a96aa3bSJed Brown           iremote[numLeaves] = roots[p-pStartF];
28940a96aa3bSJed Brown           numLeaves++;
28950a96aa3bSJed Brown         }
28960a96aa3bSJed Brown       }
28975f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(roots));
28985f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFCreate(comm,sf));
28990a96aa3bSJed Brown       if (numLeaves == (pEndF-pStartF)) {
29005f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscFree(leaves));
29015f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFSetGraph(*sf,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
29020a96aa3bSJed Brown       } else {
29035f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFSetGraph(*sf,numRoots,numLeaves,leaves,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
29040a96aa3bSJed Brown       }
29050a96aa3bSJed Brown     }
29060a96aa3bSJed Brown     if (formCids) {
29070a96aa3bSJed Brown       PetscSF  pointSF;
29080a96aa3bSJed Brown       PetscInt child;
29090a96aa3bSJed Brown 
29105f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetReferenceTree(plexF,&refTree));
29115f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetPointSF(plexF,&pointSF));
29125f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceBegin(pointSF,MPIU_INT,cids,cids,MPIU_MAX));
29135f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceEnd(pointSF,MPIU_INT,cids,cids,MPIU_MAX));
29140a96aa3bSJed Brown       if (childIds) *childIds = cids;
29150a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) {
29165f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]));
29170a96aa3bSJed Brown       }
29185f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure));
29190a96aa3bSJed Brown     }
29200a96aa3bSJed Brown   }
29210a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
29225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)*sf));
29230a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
29240a96aa3bSJed Brown     if (!childIds) {
29250a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
29260a96aa3bSJed Brown     } else {
29275f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(pEndF-pStartF,&pforestC->pointSelfToAdaptCids));
29285f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscArraycpy(pforestC->pointSelfToAdaptCids,cids,pEndF-pStartF));
29290a96aa3bSJed Brown     }
29300a96aa3bSJed Brown   } else if (saveInFine) {
29315f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)*sf));
29320a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
29330a96aa3bSJed Brown     if (!childIds) {
29340a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
29350a96aa3bSJed Brown     } else {
29365f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(pEndF-pStartF,&pforestF->pointAdaptToSelfCids));
29375f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscArraycpy(pforestF->pointAdaptToSelfCids,cids,pEndF-pStartF));
29380a96aa3bSJed Brown     }
29390a96aa3bSJed Brown   }
29405f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(treeQuads,treeQuadCounts));
29415f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(coverQuads));
29425f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(closurePointsC));
29435f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(closurePointsF));
29445f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Type_free(&nodeClosureType));
29455f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Op_free(&sfNodeReduce));
29465f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Type_free(&nodeType));
29470a96aa3bSJed Brown   PetscFunctionReturn(0);
29480a96aa3bSJed Brown }
29490a96aa3bSJed Brown 
29500a96aa3bSJed Brown /* children are sf leaves of parents */
29510a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
29520a96aa3bSJed Brown {
29530a96aa3bSJed Brown   MPI_Comm          comm;
2954d70f29a3SPierre Jolivet   PetscMPIInt       rank;
29550a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
29560a96aa3bSJed Brown   DM                plexC, plexF;
29570a96aa3bSJed Brown   PetscInt          pStartC, pEndC, pStartF, pEndF;
29580a96aa3bSJed Brown   PetscSF           pointTransferSF;
29590a96aa3bSJed Brown   PetscBool         allOnes = PETSC_TRUE;
29600a96aa3bSJed Brown 
29610a96aa3bSJed Brown   PetscFunctionBegin;
29620a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
29630a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
29642c71b3e2SJacob Faibussowitsch   PetscCheckFalse(pforestC->topo != pforestF->topo,PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
29650a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
29665f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(comm,&rank));
29670a96aa3bSJed Brown 
29680a96aa3bSJed Brown   {
29690a96aa3bSJed Brown     PetscInt i;
29700a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
29710a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
29720a96aa3bSJed Brown         allOnes = PETSC_FALSE;
29730a96aa3bSJed Brown         break;
29740a96aa3bSJed Brown       }
29750a96aa3bSJed Brown     }
29760a96aa3bSJed Brown   }
29775f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetTransferSF_Point(coarse,fine,&pointTransferSF,transferIdent,childIds));
29780a96aa3bSJed Brown   if (allOnes) {
29790a96aa3bSJed Brown     *sf = pointTransferSF;
29800a96aa3bSJed Brown     PetscFunctionReturn(0);
29810a96aa3bSJed Brown   }
29820a96aa3bSJed Brown 
29835f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(fine,&plexF));
29845f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(plexF,&pStartF,&pEndF));
29855f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(coarse,&plexC));
29865f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(plexC,&pStartC,&pEndC));
29870a96aa3bSJed Brown   {
29880a96aa3bSJed Brown     PetscInt          numRoots;
29890a96aa3bSJed Brown     PetscInt          numLeaves;
29900a96aa3bSJed Brown     const PetscInt    *leaves;
29910a96aa3bSJed Brown     const PetscSFNode *iremote;
29920a96aa3bSJed Brown     PetscInt          d;
29930a96aa3bSJed Brown     PetscSection      leafSection, rootSection;
29940a96aa3bSJed Brown     /* count leaves */
29950a96aa3bSJed Brown 
29965f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFGetGraph(pointTransferSF,&numRoots,&numLeaves,&leaves,&iremote));
29975f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF,&rootSection));
29985f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(PETSC_COMM_SELF,&leafSection));
29995f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetChart(rootSection,pStartC,pEndC));
30005f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetChart(leafSection,pStartF,pEndF));
30010a96aa3bSJed Brown 
30020a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
30030a96aa3bSJed Brown       PetscInt startC, endC, e;
30040a96aa3bSJed Brown 
30055f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSimplexOrBoxCells(plexC,P4EST_DIM-d,&startC,&endC));
30060a96aa3bSJed Brown       for (e = startC; e < endC; e++) {
30075f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionSetDof(rootSection,e,dofPerDim[d]));
30080a96aa3bSJed Brown       }
30090a96aa3bSJed Brown     }
30100a96aa3bSJed Brown 
30110a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
30120a96aa3bSJed Brown       PetscInt startF, endF, e;
30130a96aa3bSJed Brown 
30145f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetSimplexOrBoxCells(plexF,P4EST_DIM-d,&startF,&endF));
30150a96aa3bSJed Brown       for (e = startF; e < endF; e++) {
30165f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionSetDof(leafSection,e,dofPerDim[d]));
30170a96aa3bSJed Brown       }
30180a96aa3bSJed Brown     }
30190a96aa3bSJed Brown 
30205f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(rootSection));
30215f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(leafSection));
30220a96aa3bSJed Brown     {
30230a96aa3bSJed Brown       PetscInt    nroots, nleaves;
30240a96aa3bSJed Brown       PetscInt    *mine, i, p;
30250a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
30260a96aa3bSJed Brown       PetscSFNode *remote;
30270a96aa3bSJed Brown 
30285f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(pEndF-pStartF,&offsets));
30295f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(pEndC-pStartC,&offsetsRoot));
30300a96aa3bSJed Brown       for (p = pStartC; p < pEndC; p++) {
30315f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(rootSection,p,&offsetsRoot[p-pStartC]));
30320a96aa3bSJed Brown       }
30335f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE));
30345f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE));
30355f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetStorageSize(rootSection,&nroots));
30360a96aa3bSJed Brown       nleaves = 0;
30370a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
30380a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
30390a96aa3bSJed Brown         PetscInt dof;
30400a96aa3bSJed Brown 
30415f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(leafSection,leaf,&dof));
30420a96aa3bSJed Brown         nleaves += dof;
30430a96aa3bSJed Brown       }
30445f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(nleaves,&mine));
30455f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscMalloc1(nleaves,&remote));
30460a96aa3bSJed Brown       nleaves = 0;
30470a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
30480a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
30490a96aa3bSJed Brown         PetscInt dof;
30500a96aa3bSJed Brown         PetscInt off, j;
30510a96aa3bSJed Brown 
30525f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetDof(leafSection,leaf,&dof));
30535f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSectionGetOffset(leafSection,leaf,&off));
30540a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
30550a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
30560a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
30570a96aa3bSJed Brown           mine[nleaves++]       = off + j;
30580a96aa3bSJed Brown         }
30590a96aa3bSJed Brown       }
30605f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(offsetsRoot));
30615f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscFree(offsets));
30625f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFCreate(comm,sf));
30635f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetGraph(*sf,nroots,nleaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
30640a96aa3bSJed Brown     }
30655f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&leafSection));
30665f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&rootSection));
30675f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&pointTransferSF));
30680a96aa3bSJed Brown   }
30690a96aa3bSJed Brown   PetscFunctionReturn(0);
30700a96aa3bSJed Brown }
30710a96aa3bSJed Brown 
30720a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA)
30730a96aa3bSJed Brown {
30740a96aa3bSJed Brown   DM             adaptA, adaptB;
30750a96aa3bSJed Brown   DMAdaptFlag    purpose;
30760a96aa3bSJed Brown 
30770a96aa3bSJed Brown   PetscFunctionBegin;
30785f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetAdaptivityForest(dmA,&adaptA));
30795f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetAdaptivityForest(dmB,&adaptB));
30800a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
30810a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
30825f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetAdaptivityPurpose(dmA,&purpose));
30830a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
30845f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30850a96aa3bSJed Brown       PetscFunctionReturn(0);
30860a96aa3bSJed Brown     }
30870a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
30885f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetAdaptivityPurpose(dmB,&purpose));
30890a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
30905f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30910a96aa3bSJed Brown       PetscFunctionReturn(0);
30920a96aa3bSJed Brown     }
30930a96aa3bSJed Brown   }
30940a96aa3bSJed Brown   if (sfAtoB) {
30955f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetTransferSF_Internal(dmA,dmB,dofPerDim,sfAtoB,PETSC_TRUE,NULL));
30960a96aa3bSJed Brown   }
30970a96aa3bSJed Brown   if (sfBtoA) {
30985f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetTransferSF_Internal(dmB,dmA,dofPerDim,sfBtoA,(PetscBool) (sfAtoB == NULL),NULL));
30990a96aa3bSJed Brown   }
31000a96aa3bSJed Brown   PetscFunctionReturn(0);
31010a96aa3bSJed Brown }
31020a96aa3bSJed Brown 
31030a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex)
31040a96aa3bSJed Brown {
31050a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
31060a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
31070a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
31080a96aa3bSJed Brown   PetscInt          cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
31090a96aa3bSJed Brown   PetscInt          pStart, pEnd, pStartBase, pEndBase, p;
31100a96aa3bSJed Brown   DM                base;
31110a96aa3bSJed Brown   PetscInt          *star     = NULL, starSize;
31120a96aa3bSJed Brown   DMLabelLink       next      = dm->labels;
31130a96aa3bSJed Brown   PetscInt          guess     = 0;
31140a96aa3bSJed Brown   p4est_topidx_t    num_trees = pforest->topo->conn->num_trees;
31150a96aa3bSJed Brown 
31160a96aa3bSJed Brown   PetscFunctionBegin;
31170a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
31180a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
31190a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
31205f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetBaseDM(dm,&base));
31210a96aa3bSJed Brown   if (!base) {
31220a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
31230a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
31240a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
31250a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t*) p4est->trees->array;
31260a96aa3bSJed Brown       p4est_topidx_t       t, flt = p4est->first_local_tree;
31270a96aa3bSJed Brown       p4est_topidx_t       llt = pforest->forest->last_local_tree;
31280a96aa3bSJed Brown       DMLabel              ghostLabel;
31290a96aa3bSJed Brown       PetscInt             c;
31300a96aa3bSJed Brown 
31315f80ce2aSJacob Faibussowitsch       CHKERRQ(DMCreateLabel(plex,pforest->ghostName));
31325f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetLabel(plex,pforest->ghostName,&ghostLabel));
31330a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
31340a96aa3bSJed Brown         p4est_tree_t     *tree    = &trees[t];
31350a96aa3bSJed Brown         p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
31360a96aa3bSJed Brown         PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
31370a96aa3bSJed Brown         PetscInt         q;
31380a96aa3bSJed Brown 
31390a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
31400a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
31410a96aa3bSJed Brown           PetscInt         f;
31420a96aa3bSJed Brown 
31430a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
31440a96aa3bSJed Brown             p4est_quadrant_t neigh;
31450a96aa3bSJed Brown             int              isOutside;
31460a96aa3bSJed Brown 
31470a96aa3bSJed Brown             PetscStackCallP4est(p4est_quadrant_face_neighbor,(quad,f,&neigh));
31480a96aa3bSJed Brown             PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&neigh));
31490a96aa3bSJed Brown             if (isOutside) {
31500a96aa3bSJed Brown               p4est_topidx_t nt;
31510a96aa3bSJed Brown               PetscInt       nf;
31520a96aa3bSJed Brown 
31530a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
31540a96aa3bSJed Brown               nf = (PetscInt) conn->tree_to_face[t * P4EST_FACES + f];
31550a96aa3bSJed Brown               nf = nf % P4EST_FACES;
31560a96aa3bSJed Brown               if (nt == t && nf == f) {
31570a96aa3bSJed Brown                 PetscInt       plexF = P4estFaceToPetscFace[f];
31580a96aa3bSJed Brown                 const PetscInt *cone;
31590a96aa3bSJed Brown 
31605f80ce2aSJacob Faibussowitsch                 CHKERRQ(DMPlexGetCone(plex,c,&cone));
31615f80ce2aSJacob Faibussowitsch                 CHKERRQ(DMLabelSetValue(ghostLabel,cone[plexF],plexF+1));
31620a96aa3bSJed Brown               }
31630a96aa3bSJed Brown             }
31640a96aa3bSJed Brown           }
31650a96aa3bSJed Brown         }
31660a96aa3bSJed Brown       }
31670a96aa3bSJed Brown     }
31680a96aa3bSJed Brown     PetscFunctionReturn(0);
31690a96aa3bSJed Brown   }
31705f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(base,0,&cStartBase,&cEndBase));
31715f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(base,1,&fStartBase,&fEndBase));
31725f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(base,P4EST_DIM-1,&eStartBase,&eEndBase));
31735f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase));
31740a96aa3bSJed Brown 
31755f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(plex,0,&cStart,&cEnd));
31765f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(plex,1,&fStart,&fEnd));
31775f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetSimplexOrBoxCells(plex,P4EST_DIM-1,&eStart,&eEnd));
31785f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepthStratum(plex,0,&vStart,&vEnd));
31790a96aa3bSJed Brown 
31805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(plex,&pStart,&pEnd));
31815f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(base,&pStartBase,&pEndBase));
31820a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
31830a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
31840a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
31850a96aa3bSJed Brown   while (next) {
31860a96aa3bSJed Brown     DMLabel   baseLabel;
31870a96aa3bSJed Brown     DMLabel   label = next->label;
31880a96aa3bSJed Brown     PetscBool isDepth, isCellType, isGhost, isVTK, isSpmap;
31890a96aa3bSJed Brown     const char *name;
31900a96aa3bSJed Brown 
31915f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectGetName((PetscObject) label, &name));
31925f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcmp(name,"depth",&isDepth));
31930a96aa3bSJed Brown     if (isDepth) {
31940a96aa3bSJed Brown       next = next->next;
31950a96aa3bSJed Brown       continue;
31960a96aa3bSJed Brown     }
31975f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcmp(name,"celltype",&isCellType));
31980a96aa3bSJed Brown     if (isCellType) {
31990a96aa3bSJed Brown       next = next->next;
32000a96aa3bSJed Brown       continue;
32010a96aa3bSJed Brown     }
32025f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcmp(name,"ghost",&isGhost));
32030a96aa3bSJed Brown     if (isGhost) {
32040a96aa3bSJed Brown       next = next->next;
32050a96aa3bSJed Brown       continue;
32060a96aa3bSJed Brown     }
32075f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcmp(name,"vtk",&isVTK));
32080a96aa3bSJed Brown     if (isVTK) {
32090a96aa3bSJed Brown       next = next->next;
32100a96aa3bSJed Brown       continue;
32110a96aa3bSJed Brown     }
32125f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrcmp(name,"_forest_base_subpoint_map",&isSpmap));
32130a96aa3bSJed Brown     if (!isSpmap) {
32145f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetLabel(base,name,&baseLabel));
32150a96aa3bSJed Brown       if (!baseLabel) {
32160a96aa3bSJed Brown         next = next->next;
32170a96aa3bSJed Brown         continue;
32180a96aa3bSJed Brown       }
32195f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelCreateIndex(baseLabel,pStartBase,pEndBase));
32200a96aa3bSJed Brown     } else baseLabel = NULL;
32210a96aa3bSJed Brown 
32220a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
32230a96aa3bSJed Brown       PetscInt         s, c = -1, l;
32240a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
32250a96aa3bSJed Brown       p4est_quadrant_t * ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
32260a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t*) pforest->forest->trees->array;
32270a96aa3bSJed Brown       p4est_quadrant_t * q;
32280a96aa3bSJed Brown       PetscInt         t, val;
32290a96aa3bSJed Brown       PetscBool        zerosupportpoint = PETSC_FALSE;
32300a96aa3bSJed Brown 
32315f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
32320a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
32330a96aa3bSJed Brown         PetscInt point = star[2*s];
32340a96aa3bSJed Brown 
32350a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
32365f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetTransitiveClosure(plex,point,PETSC_TRUE,&closureSize,&closure));
32370a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
32380a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
32390a96aa3bSJed Brown             do { /* check parents of q */
32400a96aa3bSJed Brown               q = qParent;
32410a96aa3bSJed Brown               if (q == p) {
32420a96aa3bSJed Brown                 c = point;
32430a96aa3bSJed Brown                 break;
32440a96aa3bSJed Brown               }
32455f80ce2aSJacob Faibussowitsch               CHKERRQ(DMPlexGetTreeParent(plex,q,&qParent,NULL));
32460a96aa3bSJed Brown             } while (qParent != q);
32470a96aa3bSJed Brown             if (c != -1) break;
32485f80ce2aSJacob Faibussowitsch             CHKERRQ(DMPlexGetTreeParent(plex,pp,&pParent,NULL));
32490a96aa3bSJed Brown             q = closure[2 * l];
32500a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
32510a96aa3bSJed Brown               pp = pParent;
32520a96aa3bSJed Brown               if (pp == q) {
32530a96aa3bSJed Brown                 c = point;
32540a96aa3bSJed Brown                 break;
32550a96aa3bSJed Brown               }
32565f80ce2aSJacob Faibussowitsch               CHKERRQ(DMPlexGetTreeParent(plex,pp,&pParent,NULL));
32570a96aa3bSJed Brown             }
32580a96aa3bSJed Brown             if (c != -1) break;
32590a96aa3bSJed Brown           }
32605f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexRestoreTransitiveClosure(plex,point,PETSC_TRUE,NULL,&closure));
32610a96aa3bSJed Brown           if (l < closureSize) break;
32620a96aa3bSJed Brown         } else {
32630a96aa3bSJed Brown           PetscInt supportSize;
32640a96aa3bSJed Brown 
32655f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetSupportSize(plex,point,&supportSize));
32660a96aa3bSJed Brown           zerosupportpoint = (PetscBool) (zerosupportpoint || !supportSize);
32670a96aa3bSJed Brown         }
32680a96aa3bSJed Brown       }
32690a96aa3bSJed Brown       if (c < 0) {
32700a96aa3bSJed Brown         const char* prefix;
32710a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
32720a96aa3bSJed Brown 
32735f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
32745f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_forest_print_label_error",&print,NULL));
32750a96aa3bSJed Brown         if (print) {
32760a96aa3bSJed Brown           PetscInt i;
32770a96aa3bSJed Brown 
32785f80ce2aSJacob Faibussowitsch           CHKERRQ(PetscPrintf(PETSC_COMM_SELF,"[%d] Failed to find cell with point %D in its closure for label %s (starSize %D)\n",PetscGlobalRank,p,baseLabel ? ((PetscObject)baseLabel)->name : "_forest_base_subpoint_map",starSize));
32795f80ce2aSJacob Faibussowitsch           for (i = 0; i < starSize; i++) CHKERRQ(PetscPrintf(PETSC_COMM_SELF,"  star[%D] = %D,%D\n",i,star[2*i],star[2*i+1]));
32800a96aa3bSJed Brown         }
32815f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star));
32820a96aa3bSJed Brown         if (zerosupportpoint) continue;
328398921bdaSJacob Faibussowitsch         else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Failed to find cell with point %D 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");
32840a96aa3bSJed Brown       }
32855f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star));
32860a96aa3bSJed Brown 
32870a96aa3bSJed Brown       if (c < cLocalStart) {
32880a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
32890a96aa3bSJed Brown         q = &(ghosts[c]);
32900a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
32910a96aa3bSJed Brown       } else if (c < cLocalEnd) {
32920a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
32930a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
32940a96aa3bSJed Brown 
32950a96aa3bSJed Brown         c -= cLocalStart;
32960a96aa3bSJed Brown 
32970a96aa3bSJed Brown         do {
32980a96aa3bSJed Brown           p4est_tree_t *tree;
32990a96aa3bSJed Brown 
33002c71b3e2SJacob Faibussowitsch           PetscCheckFalse(guess < lo || guess >= num_trees || lo >= hi,PETSC_COMM_SELF,PETSC_ERR_PLIB,"failed binary search");
33010a96aa3bSJed Brown           tree = &trees[guess];
33020a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
33030a96aa3bSJed Brown             hi = guess;
33040a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt) tree->quadrants.elem_count) {
33050a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt) tree->quadrants_offset];
33060a96aa3bSJed Brown             t = guess;
33070a96aa3bSJed Brown             break;
33080a96aa3bSJed Brown           } else {
33090a96aa3bSJed Brown             lo = guess + 1;
33100a96aa3bSJed Brown           }
33110a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
33120a96aa3bSJed Brown         } while (1);
33130a96aa3bSJed Brown       } else {
33140a96aa3bSJed Brown         /* get from the end of the ghost layer */
33150a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
33160a96aa3bSJed Brown 
33170a96aa3bSJed Brown         q = &(ghosts[c]);
33180a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
33190a96aa3bSJed Brown       }
33200a96aa3bSJed Brown 
33210a96aa3bSJed Brown       if (l == 0) { /* cell */
33220a96aa3bSJed Brown         if (baseLabel) {
33235f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33240a96aa3bSJed Brown         } else {
33250a96aa3bSJed Brown           val  = t+cStartBase;
33260a96aa3bSJed Brown         }
33275f80ce2aSJacob Faibussowitsch         CHKERRQ(DMLabelSetValue(label,p,val));
33280a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
33290a96aa3bSJed Brown         p4est_quadrant_t nq;
33300a96aa3bSJed Brown         int              isInside;
33310a96aa3bSJed Brown 
33320a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
33330a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_face_neighbor,(q,l,&nq));
33340a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
33350a96aa3bSJed Brown         if (isInside) {
33360a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
33370a96aa3bSJed Brown           if (baseLabel) {
33385f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33390a96aa3bSJed Brown           } else {
33400a96aa3bSJed Brown             val  = t+cStartBase;
33410a96aa3bSJed Brown           }
33425f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelSetValue(label,p,val));
33430a96aa3bSJed Brown         } else {
33440a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
33450a96aa3bSJed Brown 
33460a96aa3bSJed Brown           if (baseLabel) {
33475f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelGetValue(baseLabel,f+fStartBase,&val));
33480a96aa3bSJed Brown           } else {
33490a96aa3bSJed Brown             val  = f+fStartBase;
33500a96aa3bSJed Brown           }
33515f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelSetValue(label,p,val));
33520a96aa3bSJed Brown         }
33530a96aa3bSJed Brown #if defined(P4_TO_P8)
33540a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
33550a96aa3bSJed Brown         p4est_quadrant_t nq;
33560a96aa3bSJed Brown         int              isInside;
33570a96aa3bSJed Brown 
33580a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
33590a96aa3bSJed Brown         PetscStackCallP4est(p8est_quadrant_edge_neighbor,(q,l,&nq));
33600a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
33610a96aa3bSJed Brown         if (isInside) {
33620a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
33630a96aa3bSJed Brown           if (baseLabel) {
33645f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33650a96aa3bSJed Brown           } else {
33660a96aa3bSJed Brown             val  = t+cStartBase;
33670a96aa3bSJed Brown           }
33685f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelSetValue(label,p,val));
33690a96aa3bSJed Brown         } else {
33700a96aa3bSJed Brown           int isOutsideFace;
33710a96aa3bSJed Brown 
33720a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutsideFace,p4est_quadrant_is_outside_face,(&nq));
33730a96aa3bSJed Brown           if (isOutsideFace) {
33740a96aa3bSJed Brown             PetscInt f;
33750a96aa3bSJed Brown 
33760a96aa3bSJed Brown             if (nq.x < 0) {
33770a96aa3bSJed Brown               f = 0;
33780a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33790a96aa3bSJed Brown               f = 1;
33800a96aa3bSJed Brown             } else if (nq.y < 0) {
33810a96aa3bSJed Brown               f = 2;
33820a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33830a96aa3bSJed Brown               f = 3;
33840a96aa3bSJed Brown             } else if (nq.z < 0) {
33850a96aa3bSJed Brown               f = 4;
33860a96aa3bSJed Brown             } else {
33870a96aa3bSJed Brown               f = 5;
33880a96aa3bSJed Brown             }
33890a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33900a96aa3bSJed Brown             if (baseLabel) {
33915f80ce2aSJacob Faibussowitsch               CHKERRQ(DMLabelGetValue(baseLabel,f+fStartBase,&val));
33920a96aa3bSJed Brown             } else {
33930a96aa3bSJed Brown               val  = f+fStartBase;
33940a96aa3bSJed Brown             }
33955f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelSetValue(label,p,val));
33960a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
33970a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
33980a96aa3bSJed Brown 
33990a96aa3bSJed Brown             if (baseLabel) {
34005f80ce2aSJacob Faibussowitsch               CHKERRQ(DMLabelGetValue(baseLabel,e+eStartBase,&val));
34010a96aa3bSJed Brown             } else {
34020a96aa3bSJed Brown               val  = e+eStartBase;
34030a96aa3bSJed Brown             }
34045f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelSetValue(label,p,val));
34050a96aa3bSJed Brown           }
34060a96aa3bSJed Brown         }
34070a96aa3bSJed Brown #endif
34080a96aa3bSJed Brown       } else { /* vertex */
34090a96aa3bSJed Brown         p4est_quadrant_t nq;
34100a96aa3bSJed Brown         int              isInside;
34110a96aa3bSJed Brown 
34120a96aa3bSJed Brown #if defined(P4_TO_P8)
34130a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
34140a96aa3bSJed Brown #else
34150a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
34160a96aa3bSJed Brown #endif
34170a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_corner_neighbor,(q,l,&nq));
34180a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
34190a96aa3bSJed Brown         if (isInside) {
34200a96aa3bSJed Brown           if (baseLabel) {
34215f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelGetValue(baseLabel,t+cStartBase,&val));
34220a96aa3bSJed Brown           } else {
34230a96aa3bSJed Brown             val  = t+cStartBase;
34240a96aa3bSJed Brown           }
34255f80ce2aSJacob Faibussowitsch           CHKERRQ(DMLabelSetValue(label,p,val));
34260a96aa3bSJed Brown         } else {
34270a96aa3bSJed Brown           int isOutside;
34280a96aa3bSJed Brown 
34290a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&nq));
34300a96aa3bSJed Brown           if (isOutside) {
34310a96aa3bSJed Brown             PetscInt f = -1;
34320a96aa3bSJed Brown 
34330a96aa3bSJed Brown             if (nq.x < 0) {
34340a96aa3bSJed Brown               f = 0;
34350a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
34360a96aa3bSJed Brown               f = 1;
34370a96aa3bSJed Brown             } else if (nq.y < 0) {
34380a96aa3bSJed Brown               f = 2;
34390a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
34400a96aa3bSJed Brown               f = 3;
34410a96aa3bSJed Brown #if defined(P4_TO_P8)
34420a96aa3bSJed Brown             } else if (nq.z < 0) {
34430a96aa3bSJed Brown               f = 4;
34440a96aa3bSJed Brown             } else {
34450a96aa3bSJed Brown               f = 5;
34460a96aa3bSJed Brown #endif
34470a96aa3bSJed Brown             }
34480a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
34490a96aa3bSJed Brown             if (baseLabel) {
34505f80ce2aSJacob Faibussowitsch               CHKERRQ(DMLabelGetValue(baseLabel,f+fStartBase,&val));
34510a96aa3bSJed Brown             } else {
34520a96aa3bSJed Brown               val  = f+fStartBase;
34530a96aa3bSJed Brown             }
34545f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelSetValue(label,p,val));
34550a96aa3bSJed Brown             continue;
34560a96aa3bSJed Brown           }
34570a96aa3bSJed Brown #if defined(P4_TO_P8)
34580a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p8est_quadrant_is_outside_edge,(&nq));
34590a96aa3bSJed Brown           if (isOutside) {
34600a96aa3bSJed Brown             /* outside edge */
34610a96aa3bSJed Brown             PetscInt e = -1;
34620a96aa3bSJed Brown 
34630a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
34640a96aa3bSJed Brown               if (nq.z < 0) {
34650a96aa3bSJed Brown                 if (nq.y < 0) {
34660a96aa3bSJed Brown                   e = 0;
34670a96aa3bSJed Brown                 } else {
34680a96aa3bSJed Brown                   e = 1;
34690a96aa3bSJed Brown                 }
34700a96aa3bSJed Brown               } else {
34710a96aa3bSJed Brown                 if (nq.y < 0) {
34720a96aa3bSJed Brown                   e = 2;
34730a96aa3bSJed Brown                 } else {
34740a96aa3bSJed Brown                   e = 3;
34750a96aa3bSJed Brown                 }
34760a96aa3bSJed Brown               }
34770a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
34780a96aa3bSJed Brown               if (nq.z < 0) {
34790a96aa3bSJed Brown                 if (nq.x < 0) {
34800a96aa3bSJed Brown                   e = 4;
34810a96aa3bSJed Brown                 } else {
34820a96aa3bSJed Brown                   e = 5;
34830a96aa3bSJed Brown                 }
34840a96aa3bSJed Brown               } else {
34850a96aa3bSJed Brown                 if (nq.x < 0) {
34860a96aa3bSJed Brown                   e = 6;
34870a96aa3bSJed Brown                 } else {
34880a96aa3bSJed Brown                   e = 7;
34890a96aa3bSJed Brown                 }
34900a96aa3bSJed Brown               }
34910a96aa3bSJed Brown             } else {
34920a96aa3bSJed Brown               if (nq.y < 0) {
34930a96aa3bSJed Brown                 if (nq.x < 0) {
34940a96aa3bSJed Brown                   e = 8;
34950a96aa3bSJed Brown                 } else {
34960a96aa3bSJed Brown                   e = 9;
34970a96aa3bSJed Brown                 }
34980a96aa3bSJed Brown               } else {
34990a96aa3bSJed Brown                 if (nq.x < 0) {
35000a96aa3bSJed Brown                   e = 10;
35010a96aa3bSJed Brown                 } else {
35020a96aa3bSJed Brown                   e = 11;
35030a96aa3bSJed Brown                 }
35040a96aa3bSJed Brown               }
35050a96aa3bSJed Brown             }
35060a96aa3bSJed Brown 
35070a96aa3bSJed Brown             e    = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
35080a96aa3bSJed Brown             if (baseLabel) {
35095f80ce2aSJacob Faibussowitsch               CHKERRQ(DMLabelGetValue(baseLabel,e+eStartBase,&val));
35100a96aa3bSJed Brown             } else {
35110a96aa3bSJed Brown               val  = e+eStartBase;
35120a96aa3bSJed Brown             }
35135f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelSetValue(label,p,val));
35140a96aa3bSJed Brown             continue;
35150a96aa3bSJed Brown           }
35160a96aa3bSJed Brown #endif
35170a96aa3bSJed Brown           {
35180a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
35190a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
35200a96aa3bSJed Brown 
35210a96aa3bSJed Brown             if (baseLabel) {
35225f80ce2aSJacob Faibussowitsch               CHKERRQ(DMLabelGetValue(baseLabel,v+vStartBase,&val));
35230a96aa3bSJed Brown             } else {
35240a96aa3bSJed Brown               val  = v+vStartBase;
35250a96aa3bSJed Brown             }
35265f80ce2aSJacob Faibussowitsch             CHKERRQ(DMLabelSetValue(label,p,val));
35270a96aa3bSJed Brown           }
35280a96aa3bSJed Brown         }
35290a96aa3bSJed Brown       }
35300a96aa3bSJed Brown     }
35310a96aa3bSJed Brown     next = next->next;
35320a96aa3bSJed Brown   }
35330a96aa3bSJed Brown   PetscFunctionReturn(0);
35340a96aa3bSJed Brown }
35350a96aa3bSJed Brown 
35360a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex)
35370a96aa3bSJed Brown {
35380a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
35390a96aa3bSJed Brown   DM                adapt;
35400a96aa3bSJed Brown 
35410a96aa3bSJed Brown   PetscFunctionBegin;
35420a96aa3bSJed Brown   if (pforest->labelsFinalized) PetscFunctionReturn(0);
35430a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
35445f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetAdaptivityForest(dm,&adapt));
35450a96aa3bSJed Brown   if (!adapt) {
35460a96aa3bSJed Brown     /* Initialize labels from the base dm */
35475f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestLabelsInitialize(dm,plex));
35480a96aa3bSJed Brown   } else {
35490a96aa3bSJed Brown     PetscInt    dofPerDim[4]={1, 1, 1, 1};
35500a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
35510a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
35520a96aa3bSJed Brown     PetscInt    *values, *adaptValues;
35530a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
35540a96aa3bSJed Brown     DMLabel     adaptLabel;
35550a96aa3bSJed Brown     DM          adaptPlex;
35560a96aa3bSJed Brown 
35575f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetAdaptivityLabel(dm,&adaptLabel));
35585f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetPlex(adapt,&adaptPlex));
35595f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetTransferSF(adapt,dm,dofPerDim,&transferForward,&transferBackward));
35605f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetChart(plex,&pStart,&pEnd));
35615f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetChart(adaptPlex,&pStartA,&pEndA));
35625f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc2(pEnd-pStart,&values,pEndA-pStartA,&adaptValues));
35635f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetPointSF(plex,&pointSF));
35640a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
35650a96aa3bSJed Brown       PetscInt p;
35660a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p-pStartA] = -1;
35670a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++)   values[p-pStart]       = -2;
35680a96aa3bSJed Brown       if (transferForward) {
35695f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
35705f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
35710a96aa3bSJed Brown       }
35720a96aa3bSJed Brown       if (transferBackward) {
35735f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
35745f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
35750a96aa3bSJed Brown       }
35760a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35770a96aa3bSJed Brown         PetscInt q = p, parent;
35780a96aa3bSJed Brown 
35795f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(plex,q,&parent,NULL));
35800a96aa3bSJed Brown         while (parent != q) {
35810a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
35820a96aa3bSJed Brown           q    = parent;
35835f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetTreeParent(plex,q,&parent,NULL));
35840a96aa3bSJed Brown         }
35850a96aa3bSJed Brown       }
35865f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX));
35875f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX));
35885f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE));
35895f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE));
35900a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35912c71b3e2SJacob Faibussowitsch         PetscCheckFalse(values[p-pStart] == -2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"uncovered point %D",p);
35920a96aa3bSJed Brown       }
35930a96aa3bSJed Brown     }
35940a96aa3bSJed Brown     while (next) {
35950a96aa3bSJed Brown       DMLabel    nextLabel = next->label;
35960a96aa3bSJed Brown       const char *name;
35970a96aa3bSJed Brown       PetscBool  isDepth, isCellType, isGhost, isVTK;
35980a96aa3bSJed Brown       DMLabel    label;
35990a96aa3bSJed Brown       PetscInt   p;
36000a96aa3bSJed Brown 
36015f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectGetName((PetscObject) nextLabel, &name));
36025f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrcmp(name,"depth",&isDepth));
36030a96aa3bSJed Brown       if (isDepth) {
36040a96aa3bSJed Brown         next = next->next;
36050a96aa3bSJed Brown         continue;
36060a96aa3bSJed Brown       }
36075f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrcmp(name,"celltype",&isCellType));
36080a96aa3bSJed Brown       if (isCellType) {
36090a96aa3bSJed Brown         next = next->next;
36100a96aa3bSJed Brown         continue;
36110a96aa3bSJed Brown       }
36125f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrcmp(name,"ghost",&isGhost));
36130a96aa3bSJed Brown       if (isGhost) {
36140a96aa3bSJed Brown         next = next->next;
36150a96aa3bSJed Brown         continue;
36160a96aa3bSJed Brown       }
36175f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscStrcmp(name,"vtk",&isVTK));
36180a96aa3bSJed Brown       if (isVTK) {
36190a96aa3bSJed Brown         next = next->next;
36200a96aa3bSJed Brown         continue;
36210a96aa3bSJed Brown       }
36220a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
36230a96aa3bSJed Brown         next = next->next;
36240a96aa3bSJed Brown         continue;
36250a96aa3bSJed Brown       }
36260a96aa3bSJed Brown       /* label was created earlier */
36275f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetLabel(dm,name,&label));
36280a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) {
36295f80ce2aSJacob Faibussowitsch         CHKERRQ(DMLabelGetValue(nextLabel,p,&adaptValues[p]));
36300a96aa3bSJed Brown       }
36310a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
36320a96aa3bSJed Brown 
36330a96aa3bSJed Brown       if (transferForward) {
36345f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
36350a96aa3bSJed Brown       }
36360a96aa3bSJed Brown       if (transferBackward) {
36375f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
36380a96aa3bSJed Brown       }
36390a96aa3bSJed Brown       if (transferForward) {
36405f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
36410a96aa3bSJed Brown       }
36420a96aa3bSJed Brown       if (transferBackward) {
36435f80ce2aSJacob Faibussowitsch         CHKERRQ(PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
36440a96aa3bSJed Brown       }
36450a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
36460a96aa3bSJed Brown         PetscInt q = p, parent;
36470a96aa3bSJed Brown 
36485f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTreeParent(plex,q,&parent,NULL));
36490a96aa3bSJed Brown         while (parent != q) {
36500a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
36510a96aa3bSJed Brown           q    = parent;
36525f80ce2aSJacob Faibussowitsch           CHKERRQ(DMPlexGetTreeParent(plex,q,&parent,NULL));
36530a96aa3bSJed Brown         }
36540a96aa3bSJed Brown       }
36555f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX));
36565f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX));
36575f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE));
36585f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE));
36590a96aa3bSJed Brown 
36600a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
36615f80ce2aSJacob Faibussowitsch         CHKERRQ(DMLabelSetValue(label,p,values[p]));
36620a96aa3bSJed Brown       }
36630a96aa3bSJed Brown       next = next->next;
36640a96aa3bSJed Brown     }
36655f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(values,adaptValues));
36665f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&transferForward));
36675f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&transferBackward));
36680a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
36690a96aa3bSJed Brown   }
36700a96aa3bSJed Brown   PetscFunctionReturn(0);
36710a96aa3bSJed Brown }
36720a96aa3bSJed Brown 
36730a96aa3bSJed 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)
36740a96aa3bSJed Brown {
36750a96aa3bSJed Brown   PetscInt       closureSize, c, coordStart, coordEnd, coordDim;
36760a96aa3bSJed Brown   PetscInt       *closure = NULL;
36770a96aa3bSJed Brown   PetscSection   coordSec;
36780a96aa3bSJed Brown 
36790a96aa3bSJed Brown   PetscFunctionBegin;
36805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateSection(plex,&coordSec));
36815f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetChart(coordSec,&coordStart,&coordEnd));
36825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDim(plex,&coordDim));
36835f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure));
36840a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
36850a96aa3bSJed Brown     PetscInt point = closure[2 * c];
36860a96aa3bSJed Brown 
36870a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
36880a96aa3bSJed Brown       PetscInt dof, off;
36890a96aa3bSJed Brown       PetscInt nCoords, i;
36905f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(coordSec,point,&dof));
36912c71b3e2SJacob Faibussowitsch       PetscCheckFalse(dof % coordDim,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
36920a96aa3bSJed Brown       nCoords = dof / coordDim;
36935f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(coordSec,point,&off));
36940a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
36950a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
36960a96aa3bSJed Brown         double      coordP4est[3]       = {0.};
36970a96aa3bSJed Brown         double      coordP4estMapped[3] = {0.};
36980a96aa3bSJed Brown         PetscInt    j;
36990a96aa3bSJed Brown         PetscReal   treeCoords[P4EST_CHILDREN][3] = {{0.}};
37000a96aa3bSJed Brown         PetscReal   eta[3]                        = {0.};
37010a96aa3bSJed Brown         PetscInt    numRounds                     = 10;
37020a96aa3bSJed Brown         PetscReal   coordGuess[3]                 = {0.};
37030a96aa3bSJed Brown 
37040a96aa3bSJed Brown         eta[0] = (PetscReal) q->x / (PetscReal) P4EST_ROOT_LEN;
37050a96aa3bSJed Brown         eta[1] = (PetscReal) q->y / (PetscReal) P4EST_ROOT_LEN;
37060a96aa3bSJed Brown #if defined(P4_TO_P8)
37070a96aa3bSJed Brown         eta[2] = (PetscReal) q->z / (PetscReal) P4EST_ROOT_LEN;
37080a96aa3bSJed Brown #endif
37090a96aa3bSJed Brown 
37100a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
37110a96aa3bSJed Brown           PetscInt k;
37120a96aa3bSJed Brown 
37130a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
37140a96aa3bSJed Brown         }
37150a96aa3bSJed Brown 
37160a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
37170a96aa3bSJed Brown           PetscInt  k;
37180a96aa3bSJed Brown           PetscReal prod = 1.;
37190a96aa3bSJed Brown 
37200a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
37210a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
37220a96aa3bSJed Brown         }
37230a96aa3bSJed Brown 
37240a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
37250a96aa3bSJed Brown           PetscInt dir;
37260a96aa3bSJed Brown 
37270a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
37280a96aa3bSJed Brown             PetscInt  k;
37290a96aa3bSJed Brown             PetscReal diff[3];
37300a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
37310a96aa3bSJed Brown             PetscReal rhs, scale, update;
37320a96aa3bSJed Brown 
37330a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
37340a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
37350a96aa3bSJed Brown               PetscInt  l;
37360a96aa3bSJed Brown               PetscReal prod = 1.;
37370a96aa3bSJed Brown 
37380a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
37390a96aa3bSJed Brown                 if (l == dir) {
37400a96aa3bSJed Brown                   prod *= (k & (1 << l)) ?  1. : -1.;
37410a96aa3bSJed Brown                 } else {
37420a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
37430a96aa3bSJed Brown                 }
37440a96aa3bSJed Brown               }
37450a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
37460a96aa3bSJed Brown             }
37470a96aa3bSJed Brown             rhs   = 0.;
37480a96aa3bSJed Brown             scale = 0;
37490a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
37500a96aa3bSJed Brown               rhs   += diff[k] * dXdeta[k];
37510a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
37520a96aa3bSJed Brown             }
37530a96aa3bSJed Brown             update    = rhs / scale;
37540a96aa3bSJed Brown             eta[dir] += update;
37550a96aa3bSJed Brown             eta[dir]  = PetscMin(eta[dir],1.);
37560a96aa3bSJed Brown             eta[dir]  = PetscMax(eta[dir],0.);
37570a96aa3bSJed Brown 
37580a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
37590a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
37600a96aa3bSJed Brown               PetscInt  l;
37610a96aa3bSJed Brown               PetscReal prod = 1.;
37620a96aa3bSJed Brown 
37630a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
37640a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
37650a96aa3bSJed Brown             }
37660a96aa3bSJed Brown           }
37670a96aa3bSJed Brown         }
37680a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double) eta[j];
37690a96aa3bSJed Brown 
37700a96aa3bSJed Brown         if (geom) {
37710a96aa3bSJed Brown           (geom->X)(geom,t,coordP4est,coordP4estMapped);
37720a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
37730a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not coded");
37740a96aa3bSJed Brown       }
37750a96aa3bSJed Brown     }
37760a96aa3bSJed Brown   }
37775f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexRestoreTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure));
37780a96aa3bSJed Brown   PetscFunctionReturn(0);
37790a96aa3bSJed Brown }
37800a96aa3bSJed Brown 
37810a96aa3bSJed Brown static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex)
37820a96aa3bSJed Brown {
37830a96aa3bSJed Brown   DM_Forest         *forest;
37840a96aa3bSJed Brown   DM_Forest_pforest *pforest;
37850a96aa3bSJed Brown   p4est_geometry_t  *geom;
37860a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd;
37870a96aa3bSJed Brown   Vec               coordLocalVec;
37880a96aa3bSJed Brown   PetscScalar       *coords;
37890a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
37900a96aa3bSJed Brown   p4est_tree_t      *trees;
37910a96aa3bSJed Brown   PetscErrorCode    (*map)(DM,PetscInt, PetscInt, const PetscReal [], PetscReal [], void*);
37920a96aa3bSJed Brown   void              *mapCtx;
37930a96aa3bSJed Brown 
37940a96aa3bSJed Brown   PetscFunctionBegin;
37950a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
37960a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
37970a96aa3bSJed Brown   geom    = pforest->topo->geom;
37985f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx));
37990a96aa3bSJed Brown   if (!geom && !map) PetscFunctionReturn(0);
38005f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinatesLocal(plex,&coordLocalVec));
38015f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(coordLocalVec,&coords));
38020a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
38030a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
38040a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
38050a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
38060a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
38070a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
38080a96aa3bSJed Brown     PetscSection coordSec;
38090a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
38100a96aa3bSJed Brown     DM           base;
38110a96aa3bSJed Brown 
38125f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
38135f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
38140a96aa3bSJed Brown     cEnd          = cEndInterior < 0 ? cEnd : cEndInterior;
38155f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetBaseDM(dm,&base));
38165f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateSection(plex,&coordSec));
38175f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetChart(coordSec,&coordStart,&coordEnd));
38185f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateDim(plex,&coordDim));
38190a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim,3);
38200a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
38210a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
38220a96aa3bSJed Brown       PetscInt dof, off, cell = -1, coarsePoint = -1;
38230a96aa3bSJed Brown       PetscInt nCoords, i;
38245f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetDof(coordSec,p,&dof));
38252c71b3e2SJacob Faibussowitsch       PetscCheckFalse(dof % coordDim,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
38260a96aa3bSJed Brown       nCoords = dof / coordDim;
38275f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(coordSec,p,&off));
38285f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
38290a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
38300a96aa3bSJed Brown         PetscInt point = star[2 * i];
38310a96aa3bSJed Brown 
38320a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
38330a96aa3bSJed Brown           cell = point;
38340a96aa3bSJed Brown           break;
38350a96aa3bSJed Brown         }
38360a96aa3bSJed Brown       }
38375f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
38380a96aa3bSJed Brown       if (cell >= 0) {
38390a96aa3bSJed Brown         if (cell < cLocalStart) {
38400a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38410a96aa3bSJed Brown 
38420a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
38430a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
38440a96aa3bSJed Brown           cell -= cLocalStart;
38450a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
38460a96aa3bSJed Brown             p4est_tree_t *tree = &(trees[t]);
38470a96aa3bSJed Brown 
38480a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t) cell < tree->quadrants_offset + tree->quadrants.elem_count) {
38490a96aa3bSJed Brown               coarsePoint = t;
38500a96aa3bSJed Brown               break;
38510a96aa3bSJed Brown             }
38520a96aa3bSJed Brown           }
38530a96aa3bSJed Brown         } else {
38540a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38550a96aa3bSJed Brown 
38560a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
38570a96aa3bSJed Brown         }
38580a96aa3bSJed Brown       }
38590a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
38600a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
38610a96aa3bSJed Brown         PetscReal   coordP4est[3]       = {0.};
38620a96aa3bSJed Brown         PetscReal   coordP4estMapped[3] = {0.};
38630a96aa3bSJed Brown         PetscInt    j;
38640a96aa3bSJed Brown 
38650a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
38665f80ce2aSJacob Faibussowitsch         CHKERRQ((map)(base,coarsePoint,p4estCoordDim,coordP4est,coordP4estMapped,mapCtx));
38670a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
38680a96aa3bSJed Brown       }
38690a96aa3bSJed Brown     }
38700a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
38710a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
38720a96aa3bSJed Brown 
38735f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
38745f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
38750a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
38760a96aa3bSJed Brown     if (cLocalStart > 0) {
38770a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38780a96aa3bSJed Brown       PetscInt         count;
38790a96aa3bSJed Brown 
38800a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
38810a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
38820a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
38830a96aa3bSJed Brown 
38845f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPforestMapCoordinates_Cell(plex,geom,count,quad,t,pforest->topo->conn,coords));
38850a96aa3bSJed Brown       }
38860a96aa3bSJed Brown     }
38870a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
38880a96aa3bSJed Brown       p4est_tree_t     *tree    = &(trees[t]);
38890a96aa3bSJed Brown       PetscInt         offset   = cLocalStart + tree->quadrants_offset, i;
38900a96aa3bSJed Brown       PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
38910a96aa3bSJed Brown       p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
38920a96aa3bSJed Brown 
38930a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
38940a96aa3bSJed Brown         PetscInt count = i + offset;
38950a96aa3bSJed Brown 
38965f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPforestMapCoordinates_Cell(plex,geom,count,&quads[i],t,pforest->topo->conn,coords));
38970a96aa3bSJed Brown       }
38980a96aa3bSJed Brown     }
38990a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
39000a96aa3bSJed Brown       p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
39010a96aa3bSJed Brown       PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
39020a96aa3bSJed Brown       PetscInt         count;
39030a96aa3bSJed Brown 
39040a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
39050a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
39060a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
39070a96aa3bSJed Brown 
39085f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPforestMapCoordinates_Cell(plex,geom,count + cLocalEnd,quad,t,pforest->topo->conn,coords));
39090a96aa3bSJed Brown       }
39100a96aa3bSJed Brown     }
39110a96aa3bSJed Brown   }
39125f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(coordLocalVec,&coords));
39130a96aa3bSJed Brown   PetscFunctionReturn(0);
39140a96aa3bSJed Brown }
39150a96aa3bSJed Brown 
39160a96aa3bSJed Brown static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
39170a96aa3bSJed Brown {
39180a96aa3bSJed Brown   DM_Forest         *forest;
39190a96aa3bSJed Brown   DM_Forest_pforest *pforest;
39200a96aa3bSJed Brown   DM                base;
39210a96aa3bSJed Brown   Vec               coordinates, cVec;
39220a96aa3bSJed Brown   PetscSection      oldSection, baseSection = NULL, newSection;
39230a96aa3bSJed Brown   const PetscScalar *coords;
39240a96aa3bSJed Brown   PetscScalar       *coords2;
39250a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, coarsePoint;
39260a96aa3bSJed Brown   PetscInt          cDim, newStart, newEnd, dof, cdof = -1;
39270a96aa3bSJed Brown   PetscInt          v, vStart, vEnd, cp, cStart, cEnd, cEndInterior, *coarsePoints;
39280a96aa3bSJed Brown   PetscInt          *localize, overlap;
39290a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
39300a96aa3bSJed Brown   p4est_tree_t      *trees;
39310a96aa3bSJed Brown   PetscBool         isper, baseLocalized = PETSC_FALSE;
39320a96aa3bSJed Brown 
39330a96aa3bSJed Brown   PetscFunctionBegin;
39345f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetPeriodicity(dm,&isper,NULL,NULL,NULL));
39350a96aa3bSJed Brown   if (!isper) PetscFunctionReturn(0);
39360a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
39375f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDim(dm, &cDim));
39380a96aa3bSJed Brown   cdof = P4EST_CHILDREN*cDim;
39395f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetBaseDM(dm,&base));
39400a96aa3bSJed Brown   if (base) {
39415f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinatesLocalized(base,&baseLocalized));
39420a96aa3bSJed Brown   }
39430a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
39445f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetChart(plex, &newStart, &newEnd));
39450a96aa3bSJed Brown 
39465f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetPartitionOverlap(dm,&overlap));
39475f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscCalloc1(overlap ? newEnd - newStart : 0,&localize));
39480a96aa3bSJed Brown 
39495f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &newSection));
39505f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetNumFields(newSection, 1));
39515f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetFieldComponents(newSection, 0, cDim));
39525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetChart(newSection, newStart, newEnd));
39530a96aa3bSJed Brown 
39545f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateSection(plex, &oldSection));
39555f80ce2aSJacob Faibussowitsch   if (base) CHKERRQ(DMGetCoordinateSection(base, &baseSection));
39565f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetDepthStratum(plex,0,&vStart,&vEnd));
39570a96aa3bSJed Brown   for (v = vStart; v < vEnd; ++v) {
39585f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(oldSection, v, &dof));
39595f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetDof(newSection, v, dof));
39605f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetFieldDof(newSection, v, 0, dof));
39610a96aa3bSJed Brown     if (overlap) localize[v] = dof;
39620a96aa3bSJed Brown   }
39630a96aa3bSJed Brown 
39640a96aa3bSJed Brown   forest      = (DM_Forest*) dm->data;
39650a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
39660a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
39670a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
39680a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
39690a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
39700a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
39710a96aa3bSJed Brown 
39720a96aa3bSJed Brown   cp = 0;
39735f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
39745f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
39750a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
39765f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc1(cEnd-cStart,&coarsePoints));
39770a96aa3bSJed Brown   if (cLocalStart > 0) {
39780a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
39790a96aa3bSJed Brown     PetscInt         count;
39800a96aa3bSJed Brown 
39810a96aa3bSJed Brown     for (count = 0; count < cLocalStart; count++) {
39820a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count];
39830a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
39840a96aa3bSJed Brown 
39855f80ce2aSJacob Faibussowitsch       if (baseSection) CHKERRQ(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
39865f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(newSection, count, cdof));
39875f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetFieldDof(newSection, count, 0, cdof));
39880a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
39890a96aa3bSJed Brown       if (overlap) localize[count] = cdof;
39900a96aa3bSJed Brown     }
39910a96aa3bSJed Brown   }
39920a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
39930a96aa3bSJed Brown     p4est_tree_t *tree    = &(trees[t]);
39940a96aa3bSJed Brown     PetscInt     offset   = cLocalStart + tree->quadrants_offset;
39950a96aa3bSJed Brown     PetscInt     numQuads = (PetscInt) tree->quadrants.elem_count;
39960a96aa3bSJed Brown     PetscInt     i;
39970a96aa3bSJed Brown 
39980a96aa3bSJed Brown     if (!numQuads) continue;
39990a96aa3bSJed Brown     coarsePoint = t;
40005f80ce2aSJacob Faibussowitsch     if (baseSection) CHKERRQ(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
40010a96aa3bSJed Brown     for (i = 0; i < numQuads; i++) {
40020a96aa3bSJed Brown       PetscInt newCell = i + offset;
40030a96aa3bSJed Brown 
40045f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(newSection, newCell, cdof));
40055f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
40060a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
40070a96aa3bSJed Brown       if (overlap) localize[newCell] = cdof;
40080a96aa3bSJed Brown     }
40090a96aa3bSJed Brown   }
40100a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
40110a96aa3bSJed Brown     p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
40120a96aa3bSJed Brown     PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
40130a96aa3bSJed Brown     PetscInt         count;
40140a96aa3bSJed Brown 
40150a96aa3bSJed Brown     for (count = 0; count < numGhosts - cLocalStart; count++) {
40160a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
40170a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
40180a96aa3bSJed Brown       PetscInt newCell = count + cLocalEnd;
40190a96aa3bSJed Brown 
40205f80ce2aSJacob Faibussowitsch       if (baseSection) CHKERRQ(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
40215f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(newSection, newCell, cdof));
40225f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
40230a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
40240a96aa3bSJed Brown       if (overlap) localize[newCell] = cdof;
40250a96aa3bSJed Brown     }
40260a96aa3bSJed Brown   }
40272c71b3e2SJacob Faibussowitsch   PetscCheckFalse(cp != cEnd - cStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected number of fine cells %D != %D",cp,cEnd-cStart);
40280a96aa3bSJed Brown 
40290a96aa3bSJed Brown   if (base) { /* we need to localize on all the cells in the star of the coarse cell vertices */
40300a96aa3bSJed Brown     PetscInt *closure = NULL, closureSize;
40310a96aa3bSJed Brown     PetscInt p, i, c, vStartBase, vEndBase, cStartBase, cEndBase;
40320a96aa3bSJed Brown 
40335f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetHeightStratum(base,0,&cStartBase,&cEndBase));
40345f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase));
40350a96aa3bSJed Brown     for (p = cStart; p < cEnd; p++) {
40360a96aa3bSJed Brown       coarsePoint = coarsePoints[p-cStart];
40370a96aa3bSJed Brown       if (coarsePoint < 0) continue;
40385f80ce2aSJacob Faibussowitsch       if (baseSection) CHKERRQ(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
40395f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexGetTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure));
40400a96aa3bSJed Brown       for (c = 0; c < closureSize; c++) {
40410a96aa3bSJed Brown         PetscInt *star = NULL, starSize;
40420a96aa3bSJed Brown         PetscInt j, v = closure[2 * c];
40430a96aa3bSJed Brown 
40440a96aa3bSJed Brown         if (v < vStartBase || v > vEndBase) continue;
40455f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexGetTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star));
40460a96aa3bSJed Brown         for (j = 0; j < starSize; j++) {
40470a96aa3bSJed Brown           PetscInt cell = star[2 * j];
40480a96aa3bSJed Brown 
40490a96aa3bSJed Brown           if (cStartBase <= cell && cell < cEndBase) {
40500a96aa3bSJed Brown             p4est_tree_t *tree;
40510a96aa3bSJed Brown             PetscInt     offset,numQuads;
40520a96aa3bSJed Brown 
40530a96aa3bSJed Brown             if (cell < flt || cell > llt) continue;
40540a96aa3bSJed Brown             tree     = &(trees[cell]);
40550a96aa3bSJed Brown             offset   = cLocalStart + tree->quadrants_offset;
40560a96aa3bSJed Brown             numQuads = (PetscInt) tree->quadrants.elem_count;
40570a96aa3bSJed Brown             for (i = 0; i < numQuads; i++) {
40580a96aa3bSJed Brown               PetscInt newCell = i + offset;
40590a96aa3bSJed Brown 
40605f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionSetDof(newSection, newCell, cdof));
40615f80ce2aSJacob Faibussowitsch               CHKERRQ(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
40620a96aa3bSJed Brown               if (overlap) localize[newCell] = cdof;
40630a96aa3bSJed Brown             }
40640a96aa3bSJed Brown           }
40650a96aa3bSJed Brown         }
40665f80ce2aSJacob Faibussowitsch         CHKERRQ(DMPlexRestoreTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star));
40670a96aa3bSJed Brown       }
40685f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexRestoreTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure));
40690a96aa3bSJed Brown     }
40700a96aa3bSJed Brown   }
40715f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(coarsePoints));
40720a96aa3bSJed Brown 
40730a96aa3bSJed Brown   /* final consensus with overlap */
40740a96aa3bSJed Brown   if (overlap) {
40750a96aa3bSJed Brown     PetscSF  sf;
40760a96aa3bSJed Brown     PetscInt *localizeGlobal;
40770a96aa3bSJed Brown 
40785f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetPointSF(plex,&sf));
40795f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(newEnd-newStart,&localizeGlobal));
40800a96aa3bSJed Brown     for (v = newStart; v < newEnd; v++) localizeGlobal[v - newStart] = localize[v - newStart];
40815f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastBegin(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE));
40825f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastEnd(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE));
40830a96aa3bSJed Brown     for (v = newStart; v < newEnd; v++) {
40845f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(newSection, v, localizeGlobal[v-newStart]));
40855f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetFieldDof(newSection, v, 0, localizeGlobal[v-newStart]));
40860a96aa3bSJed Brown     }
40875f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(localizeGlobal));
40880a96aa3bSJed Brown   }
40895f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(localize));
40905f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionSetUp(newSection));
40915f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectReference((PetscObject)oldSection));
40925f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetCoordinateSection(plex, cDim, newSection));
40935f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetStorageSize(newSection, &v));
40945f80ce2aSJacob Faibussowitsch   CHKERRQ(VecCreate(PETSC_COMM_SELF, &cVec));
40955f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectSetName((PetscObject)cVec,"coordinates"));
40965f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetBlockSize(cVec, cDim));
40975f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetSizes(cVec, v, PETSC_DETERMINE));
40985f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetType(cVec, VECSTANDARD));
40995f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSet(cVec, PETSC_MIN_REAL));
41000a96aa3bSJed Brown 
41010a96aa3bSJed Brown   /* Copy over vertex coordinates */
41025f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinatesLocal(plex, &coordinates));
4103*28b400f6SJacob Faibussowitsch   PetscCheck(coordinates,PetscObjectComm((PetscObject)plex),PETSC_ERR_SUP,"Missing local coordinates vector");
41045f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArray(cVec, &coords2));
41055f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetArrayRead(coordinates, &coords));
41060a96aa3bSJed Brown   for (v = vStart; v < vEnd; ++v) {
41070a96aa3bSJed Brown     PetscInt d, off,off2;
41080a96aa3bSJed Brown 
41095f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetDof(oldSection, v, &dof));
41105f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(oldSection, v, &off));
41115f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetOffset(newSection, v, &off2));
41120a96aa3bSJed Brown     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
41130a96aa3bSJed Brown   }
41145f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArrayRead(coordinates, &coords));
41150a96aa3bSJed Brown 
41160a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
41170a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
41180a96aa3bSJed Brown     p4est_tree_t     *tree    = &(trees[t]);
41190a96aa3bSJed Brown     const double     *v       = pforest->topo->conn->vertices;
41200a96aa3bSJed Brown     p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
41210a96aa3bSJed Brown     PetscInt         offset   = cLocalStart + tree->quadrants_offset;
41220a96aa3bSJed Brown     PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
41230a96aa3bSJed Brown     p4est_topidx_t   vt[8]    = {0,0,0,0,0,0,0,0};
41240a96aa3bSJed Brown     PetscInt         i,k;
41250a96aa3bSJed Brown 
41260a96aa3bSJed Brown     if (!numQuads) continue;
41270a96aa3bSJed Brown     for (k = 0; k < P4EST_CHILDREN; ++k) {
41280a96aa3bSJed Brown       vt[k] = pforest->topo->conn->tree_to_vertex[t * P4EST_CHILDREN + k];
41290a96aa3bSJed Brown     }
41300a96aa3bSJed Brown 
41310a96aa3bSJed Brown     for (i = 0; i < numQuads; i++) {
41320a96aa3bSJed Brown       p4est_quadrant_t  *quad = &quads[i];
41330a96aa3bSJed Brown       const PetscReal   intsize = 1.0 / P4EST_ROOT_LEN;
41340a96aa3bSJed Brown       PetscReal         h2;
41350a96aa3bSJed Brown       PetscScalar       xyz[3];
41360a96aa3bSJed Brown #ifdef P4_TO_P8
41370a96aa3bSJed Brown       PetscInt          zi;
41380a96aa3bSJed Brown #endif
41390a96aa3bSJed Brown       PetscInt          yi,xi;
41400a96aa3bSJed Brown       PetscInt          off2;
41410a96aa3bSJed Brown       PetscInt          newCell = i + offset;
41420a96aa3bSJed Brown 
41435f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetFieldDof(newSection, newCell, 0, &cdof));
41440a96aa3bSJed Brown       if (!cdof) continue;
41450a96aa3bSJed Brown 
41460a96aa3bSJed Brown       h2   = .5 * intsize * P4EST_QUADRANT_LEN (quad->level);
41470a96aa3bSJed Brown       k    = 0;
41485f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionGetOffset(newSection, newCell, &off2));
41490a96aa3bSJed Brown #ifdef P4_TO_P8
41500a96aa3bSJed Brown       for (zi = 0; zi < 2; ++zi) {
41510a96aa3bSJed Brown         const PetscReal eta_z = intsize * quad->z + h2 * (1. + (zi * 2 - 1));
41520a96aa3bSJed Brown #else
41530a96aa3bSJed Brown       {
41540a96aa3bSJed Brown         const PetscReal eta_z = 0.0;
41550a96aa3bSJed Brown #endif
41560a96aa3bSJed Brown         for (yi = 0; yi < 2; ++yi) {
41570a96aa3bSJed Brown           const PetscReal eta_y = intsize * quad->y + h2 * (1. + (yi * 2 - 1));
41580a96aa3bSJed Brown           for (xi = 0; xi < 2; ++xi) {
41590a96aa3bSJed Brown             const PetscReal eta_x = intsize * quad->x + h2 * (1. + (xi * 2 - 1));
41600a96aa3bSJed Brown             PetscInt    j;
41610a96aa3bSJed Brown 
41620a96aa3bSJed Brown             for (j = 0; j < 3; ++j) {
41630a96aa3bSJed Brown               xyz[j] = ((1. - eta_z) * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[0] + j] +
41640a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[1] + j]) +
41650a96aa3bSJed Brown                                               eta_y  * ((1. - eta_x) * v[3 * vt[2] + j] +
41660a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[3] + j]))
41670a96aa3bSJed Brown                         +     eta_z  * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[4] + j] +
41680a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[5] + j]) +
41690a96aa3bSJed Brown                                               eta_y  * ((1. - eta_x) * v[3 * vt[6] + j] +
41700a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[7] + j])));
41710a96aa3bSJed Brown             }
41720a96aa3bSJed Brown             for (j = 0; j < cDim; ++j) coords2[off2 + cDim*P4estVertToPetscVert[k] + j] = xyz[j];
41730a96aa3bSJed Brown             ++k;
41740a96aa3bSJed Brown           }
41750a96aa3bSJed Brown         }
41760a96aa3bSJed Brown       }
41770a96aa3bSJed Brown     }
41780a96aa3bSJed Brown   }
41795f80ce2aSJacob Faibussowitsch   CHKERRQ(VecRestoreArray(cVec, &coords2));
41805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetCoordinatesLocal(plex, cVec));
41815f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&cVec));
41825f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&newSection));
41835f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionDestroy(&oldSection));
41840a96aa3bSJed Brown   PetscFunctionReturn(0);
41850a96aa3bSJed Brown }
41860a96aa3bSJed Brown 
41870a96aa3bSJed Brown #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
41880a96aa3bSJed Brown static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
41890a96aa3bSJed Brown {
41900a96aa3bSJed Brown   DM_Forest         *forest;
41910a96aa3bSJed Brown   DM_Forest_pforest *pforest;
41920a96aa3bSJed Brown 
41930a96aa3bSJed Brown   PetscFunctionBegin;
41940a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
41950a96aa3bSJed Brown   pforest = (DM_Forest_pforest *) forest->data;
41965f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFDestroy(&(pforest->pointAdaptToSelfSF)));
41975f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFDestroy(&(pforest->pointSelfToAdaptSF)));
41985f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(pforest->pointAdaptToSelfCids));
41995f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(pforest->pointSelfToAdaptCids));
42000a96aa3bSJed Brown   PetscFunctionReturn(0);
42010a96aa3bSJed Brown }
42020a96aa3bSJed Brown 
42030a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
42040a96aa3bSJed Brown {
42050a96aa3bSJed Brown   DM_Forest            *forest;
42060a96aa3bSJed Brown   DM_Forest_pforest    *pforest;
42070a96aa3bSJed Brown   DM                   refTree, newPlex, base;
42080a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
42090a96aa3bSJed Brown   MPI_Comm             comm;
42100a96aa3bSJed Brown   PetscBool            isPforest;
42110a96aa3bSJed Brown   PetscInt             dim;
42120a96aa3bSJed Brown   PetscInt             overlap;
42130a96aa3bSJed Brown   p4est_connect_type_t ctype;
42140a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
42150a96aa3bSJed Brown   sc_array_t           *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
42160a96aa3bSJed Brown   PetscSection         parentSection;
42170a96aa3bSJed Brown   PetscSF              pointSF;
42180a96aa3bSJed Brown   size_t               zz, count;
42190a96aa3bSJed Brown   PetscInt             pStart, pEnd;
42200a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
42210a96aa3bSJed Brown 
42220a96aa3bSJed Brown   PetscFunctionBegin;
42230a96aa3bSJed Brown 
42240a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
42250a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
42265f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectTypeCompare((PetscObject)dm,DMPFOREST,&isPforest));
4227*28b400f6SJacob Faibussowitsch   PetscCheck(isPforest,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPFOREST,((PetscObject)dm)->type_name);
42285f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimension(dm,&dim));
42292c71b3e2SJacob Faibussowitsch   PetscCheckFalse(dim != P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %d",P4EST_DIM,dim);
42300a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
42310a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
42325f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetBaseDM(dm,&base));
42330a96aa3bSJed Brown   if (base) {
42345f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLabel(base,"ghost",&ghostLabelBase));
42350a96aa3bSJed Brown   }
42360a96aa3bSJed Brown   if (!pforest->plex) {
42370a96aa3bSJed Brown     PetscMPIInt size;
42380a96aa3bSJed Brown 
42395f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Comm_size(comm,&size));
42405f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreate(comm,&newPlex));
42415f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetType(newPlex,DMPLEX));
42425f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetMatType(newPlex,dm->mattype));
42430a96aa3bSJed Brown     /* share labels */
42445f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
42455f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetAdjacencyDimension(dm,&adjDim));
42465f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetAdjacencyCodimension(dm,&adjCodim));
42475f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateDim(dm,&coordDim));
42480a96aa3bSJed Brown     if (adjDim == 0) {
42490a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
42500a96aa3bSJed Brown     } else if (adjCodim == 1) {
42510a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
42520a96aa3bSJed Brown #if defined(P4_TO_P8)
42530a96aa3bSJed Brown     } else if (adjDim == 1) {
42540a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
42550a96aa3bSJed Brown #endif
42560a96aa3bSJed Brown     } else {
425798921bdaSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Invalid adjacency dimension %d",adjDim);
42580a96aa3bSJed Brown     }
42592c71b3e2SJacob Faibussowitsch     PetscCheckFalse(ctype != P4EST_CONNECT_FULL,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Adjacency dimension %D / codimension %D not supported yet",adjDim,adjCodim);
42605f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestGetPartitionOverlap(dm,&overlap));
42610a96aa3bSJed Brown     ((DM_Plex *) newPlex->data)->overlap = overlap;
42620a96aa3bSJed Brown 
42630a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
42640a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
42650a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
42660a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
42670a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
42680a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
42690a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
42700a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
42710a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
42720a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
42730a96aa3bSJed Brown 
42740a96aa3bSJed 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));
42750a96aa3bSJed Brown 
42760a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt) first_local_quad;
42770a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt) pforest->forest->local_num_quadrants;
42785f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(points_per_dim));
42795f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(cone_sizes));
42805f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(cones));
42815f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(cone_orientations));
42825f80ce2aSJacob Faibussowitsch     CHKERRQ(coords_double_to_PetscScalar(coords, coordDim));
42835f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(children));
42845f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(parents));
42855f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(childids));
42865f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_to_PetscInt(leaves));
42875f80ce2aSJacob Faibussowitsch     CHKERRQ(locidx_pair_to_PetscSFNode(remotes));
42880a96aa3bSJed Brown 
42895f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetDimension(newPlex,P4EST_DIM));
42905f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetCoordinateDim(newPlex,coordDim));
42915f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetMaxProjectionHeight(newPlex,P4EST_DIM - 1));
42925f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexCreateFromDAG(newPlex,P4EST_DIM,(PetscInt*)points_per_dim->array,(PetscInt*)cone_sizes->array,(PetscInt*)cones->array,(PetscInt*)cone_orientations->array,(PetscScalar*)coords->array));
42935f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexConvertOldOrientations_Internal(newPlex));
42945f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreateReferenceTree_pforest(comm,&refTree));
42955f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetReferenceTree(newPlex,refTree));
42965f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(comm,&parentSection));
42975f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetChart(newPlex,&pStart,&pEnd));
42985f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetChart(parentSection,pStart,pEnd));
42990a96aa3bSJed Brown     count = children->elem_count;
43000a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
43010a96aa3bSJed Brown       PetscInt child = *((PetscInt*) sc_array_index(children,zz));
43020a96aa3bSJed Brown 
43035f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSectionSetDof(parentSection,child,1));
43040a96aa3bSJed Brown     }
43055f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionSetUp(parentSection));
43065f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexSetTree(newPlex,parentSection,(PetscInt*)parents->array,(PetscInt*)childids->array));
43075f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&parentSection));
43085f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreate(comm,&pointSF));
43090a96aa3bSJed Brown     /*
43100a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
43110a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
43120a96aa3bSJed Brown     */
43135f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetGraph(pointSF,pEnd - pStart,(PetscInt)leaves->elem_count,(PetscInt*)leaves->array,PETSC_COPY_VALUES,(PetscSFNode*)remotes->array,PETSC_COPY_VALUES));
43145f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetPointSF(newPlex,pointSF));
43155f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetPointSF(dm,pointSF));
43160a96aa3bSJed Brown     {
43170a96aa3bSJed Brown       DM coordDM;
43180a96aa3bSJed Brown 
43195f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinateDM(newPlex,&coordDM));
43205f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetPointSF(coordDM,pointSF));
43210a96aa3bSJed Brown     }
43225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&pointSF));
43230a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
43240a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
43250a96aa3bSJed Brown     sc_array_destroy (cones);
43260a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
43270a96aa3bSJed Brown     sc_array_destroy (coords);
43280a96aa3bSJed Brown     sc_array_destroy (children);
43290a96aa3bSJed Brown     sc_array_destroy (parents);
43300a96aa3bSJed Brown     sc_array_destroy (childids);
43310a96aa3bSJed Brown     sc_array_destroy (leaves);
43320a96aa3bSJed Brown     sc_array_destroy (remotes);
43330a96aa3bSJed Brown 
43340a96aa3bSJed Brown     {
43350a96aa3bSJed Brown       PetscBool             isper;
43360a96aa3bSJed Brown       const PetscReal      *maxCell, *L;
43370a96aa3bSJed Brown       const DMBoundaryType *bd;
43380a96aa3bSJed Brown 
43395f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd));
43405f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetPeriodicity(newPlex,isper,maxCell,L,bd));
43415f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestLocalizeCoordinates(dm,newPlex));
43420a96aa3bSJed Brown     }
43430a96aa3bSJed Brown 
43440a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
43450a96aa3bSJed Brown       Vec               coordsGlobal, coordsLocal;
43460a96aa3bSJed Brown       const PetscScalar *globalArray;
43470a96aa3bSJed Brown       PetscScalar       *localArray;
43480a96aa3bSJed Brown       PetscSF           coordSF;
43490a96aa3bSJed Brown       DM                coordDM;
43500a96aa3bSJed Brown 
43515f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinateDM(newPlex,&coordDM));
43525f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetSectionSF(coordDM,&coordSF));
43535f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinates(newPlex, &coordsGlobal));
43545f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinatesLocal(newPlex, &coordsLocal));
43555f80ce2aSJacob Faibussowitsch       CHKERRQ(VecGetArrayRead(coordsGlobal, &globalArray));
43565f80ce2aSJacob Faibussowitsch       CHKERRQ(VecGetArray(coordsLocal, &localArray));
43575f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastBegin(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
43585f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFBcastEnd(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
43595f80ce2aSJacob Faibussowitsch       CHKERRQ(VecRestoreArray(coordsLocal, &localArray));
43605f80ce2aSJacob Faibussowitsch       CHKERRQ(VecRestoreArrayRead(coordsGlobal, &globalArray));
43615f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetCoordinatesLocal(newPlex, coordsLocal));
43620a96aa3bSJed Brown     }
43635f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestMapCoordinates(dm,newPlex));
43640a96aa3bSJed Brown 
43650a96aa3bSJed Brown     pforest->plex = newPlex;
43660a96aa3bSJed Brown 
43670a96aa3bSJed Brown     /* copy labels */
43685f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestLabelsFinalize(dm,newPlex));
43690a96aa3bSJed Brown 
43700a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
43710a96aa3bSJed Brown       PetscInt numAdded;
43720a96aa3bSJed Brown       DM       newPlexGhosted;
43730a96aa3bSJed Brown       void     *ctx;
43740a96aa3bSJed Brown 
43755f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexConstructGhostCells(newPlex,pforest->ghostName,&numAdded,&newPlexGhosted));
43765f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetApplicationContext(newPlex,&ctx));
43775f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetApplicationContext(newPlexGhosted,ctx));
43780a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
43795f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetPointSF(newPlexGhosted,&pointSF));
43805f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetPointSF(dm,pointSF));
43815f80ce2aSJacob Faibussowitsch       CHKERRQ(DMDestroy(&newPlex));
43825f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPlexSetReferenceTree(newPlexGhosted,refTree));
43835f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestClearAdaptivityForest_pforest(dm));
43840a96aa3bSJed Brown       newPlex = newPlexGhosted;
43850a96aa3bSJed Brown 
43860a96aa3bSJed Brown       /* share the labels back */
43875f80ce2aSJacob Faibussowitsch       CHKERRQ(DMDestroyLabelLinkList_Internal(dm));
43885f80ce2aSJacob Faibussowitsch       CHKERRQ(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
43890a96aa3bSJed Brown       pforest->plex = newPlex;
43900a96aa3bSJed Brown     }
43915f80ce2aSJacob Faibussowitsch     CHKERRQ(DMDestroy(&refTree));
43920a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
43935f80ce2aSJacob Faibussowitsch       PetscErrorCode ierr;
43945f80ce2aSJacob Faibussowitsch 
43950a96aa3bSJed Brown       ierr = PetscObjectOptionsBegin((PetscObject)newPlex);CHKERRQ(ierr);
43965f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject,newPlex));
43975f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)newPlex));
43980a96aa3bSJed Brown       ierr = PetscOptionsEnd();CHKERRQ(ierr);
43990a96aa3bSJed Brown     }
44005f80ce2aSJacob Faibussowitsch     CHKERRQ(DMViewFromOptions(newPlex,NULL,"-dm_p4est_plex_view"));
44010a96aa3bSJed Brown     {
44020a96aa3bSJed Brown       PetscSection coordsSec;
44030a96aa3bSJed Brown       Vec          coords;
44040a96aa3bSJed Brown       PetscInt     cDim;
44050a96aa3bSJed Brown 
44065f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinateDim(newPlex,&cDim));
44075f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinateSection(newPlex,&coordsSec));
44085f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetCoordinateSection(dm,cDim,coordsSec));
44095f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoordinatesLocal(newPlex,&coords));
44105f80ce2aSJacob Faibussowitsch       CHKERRQ(DMSetCoordinatesLocal(dm,coords));
44110a96aa3bSJed Brown     }
44120a96aa3bSJed Brown   }
44130a96aa3bSJed Brown   newPlex = pforest->plex;
44140a96aa3bSJed Brown   if (plex) {
44150a96aa3bSJed Brown     DM coordDM;
44160a96aa3bSJed Brown 
44175f80ce2aSJacob Faibussowitsch     CHKERRQ(DMClone(newPlex,plex));
44185f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetCoordinateDM(newPlex,&coordDM));
44195f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetCoordinateDM(*plex,coordDM));
44205f80ce2aSJacob Faibussowitsch     CHKERRQ(DMShareDiscretization(dm,*plex));
44210a96aa3bSJed Brown   }
44220a96aa3bSJed Brown   PetscFunctionReturn(0);
44230a96aa3bSJed Brown }
44240a96aa3bSJed Brown 
44250a96aa3bSJed Brown static PetscErrorCode DMSetFromOptions_pforest(PetscOptionItems *PetscOptionsObject,DM dm)
44260a96aa3bSJed Brown {
44270a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44280a96aa3bSJed Brown   char              stringBuffer[256];
44290a96aa3bSJed Brown   PetscBool         flg;
44300a96aa3bSJed Brown 
44310a96aa3bSJed Brown   PetscFunctionBegin;
44325f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetFromOptions_Forest(PetscOptionsObject,dm));
44335f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsHead(PetscOptionsObject,"DM" P4EST_STRING " options"));
44345f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsBool("-dm_p4est_partition_for_coarsening","partition forest to allow for coarsening","DMP4estSetPartitionForCoarsening",pforest->partition_for_coarsening,&(pforest->partition_for_coarsening),NULL));
44355f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsString("-dm_p4est_ghost_label_name","the name of the ghost label when converting from a DMPlex",NULL,NULL,stringBuffer,sizeof(stringBuffer),&flg));
44365f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscOptionsTail());
44370a96aa3bSJed Brown   if (flg) {
44385f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(pforest->ghostName));
44395f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscStrallocpy(stringBuffer,&pforest->ghostName));
44400a96aa3bSJed Brown   }
44410a96aa3bSJed Brown   PetscFunctionReturn(0);
44420a96aa3bSJed Brown }
44430a96aa3bSJed Brown 
44440a96aa3bSJed Brown #if !defined(P4_TO_P8)
44450a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
44460a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
44470a96aa3bSJed Brown #else
44480a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
44490a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
44500a96aa3bSJed Brown #endif
44510a96aa3bSJed Brown 
44520a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
44530a96aa3bSJed Brown {
44540a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44550a96aa3bSJed Brown 
44560a96aa3bSJed Brown   PetscFunctionBegin;
44570a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
44580a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44590a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
44600a96aa3bSJed Brown   PetscFunctionReturn(0);
44610a96aa3bSJed Brown }
44620a96aa3bSJed Brown 
44630a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
44640a96aa3bSJed Brown {
44650a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44660a96aa3bSJed Brown 
44670a96aa3bSJed Brown   PetscFunctionBegin;
44680a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
44690a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44700a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
44710a96aa3bSJed Brown   PetscFunctionReturn(0);
44720a96aa3bSJed Brown }
44730a96aa3bSJed Brown 
44740a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM dm,DM *plex)
44750a96aa3bSJed Brown {
44760a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44770a96aa3bSJed Brown 
44780a96aa3bSJed Brown   PetscFunctionBegin;
44790a96aa3bSJed Brown   if (plex) *plex = NULL;
44805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetUp(dm));
44810a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44820a96aa3bSJed Brown   if (!pforest->plex) {
44835f80ce2aSJacob Faibussowitsch     CHKERRQ(DMConvert_pforest_plex(dm,DMPLEX,NULL));
44840a96aa3bSJed Brown   }
44855f80ce2aSJacob Faibussowitsch   CHKERRQ(DMShareDiscretization(dm,pforest->plex));
44860a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
44870a96aa3bSJed Brown   PetscFunctionReturn(0);
44880a96aa3bSJed Brown }
44890a96aa3bSJed Brown 
44900a96aa3bSJed Brown #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
44910a96aa3bSJed Brown static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
44920a96aa3bSJed Brown {
44930a96aa3bSJed Brown   PetscSection   gsc, gsf;
44940a96aa3bSJed Brown   PetscInt       m, n;
44950a96aa3bSJed Brown   DM             cdm;
44960a96aa3bSJed Brown 
44970a96aa3bSJed Brown   PetscFunctionBegin;
44985f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(dmFine, &gsf));
44995f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetConstrainedStorageSize(gsf, &m));
45005f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(dmCoarse, &gsc));
45015f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetConstrainedStorageSize(gsc, &n));
45020a96aa3bSJed Brown 
45035f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(PetscObjectComm((PetscObject) dmFine), interpolation));
45045f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
45055f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetType(*interpolation, MATAIJ));
45060a96aa3bSJed Brown 
45075f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoarseDM(dmFine, &cdm));
45082c71b3e2SJacob Faibussowitsch   PetscCheckFalse(cdm != dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only interpolation from coarse DM for now");
45090a96aa3bSJed Brown 
45100a96aa3bSJed Brown   {
45110a96aa3bSJed Brown     DM       plexF, plexC;
45120a96aa3bSJed Brown     PetscSF  sf;
45130a96aa3bSJed Brown     PetscInt *cids;
45140a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
45150a96aa3bSJed Brown 
45165f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetPlex(dmCoarse,&plexC));
45175f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetPlex(dmFine,&plexF));
45185f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
45195f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetUp(sf));
45205f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
45215f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&sf));
45225f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(cids));
45230a96aa3bSJed Brown   }
45245f80ce2aSJacob Faibussowitsch   CHKERRQ(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
45250a96aa3bSJed Brown   /* Use naive scaling */
45265f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
45270a96aa3bSJed Brown   PetscFunctionReturn(0);
45280a96aa3bSJed Brown }
45290a96aa3bSJed Brown 
45300a96aa3bSJed Brown #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
45310a96aa3bSJed Brown static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
45320a96aa3bSJed Brown {
45330a96aa3bSJed Brown   PetscSection   gsc, gsf;
45340a96aa3bSJed Brown   PetscInt       m, n;
45350a96aa3bSJed Brown   DM             cdm;
45360a96aa3bSJed Brown 
45370a96aa3bSJed Brown   PetscFunctionBegin;
45385f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(dmFine, &gsf));
45395f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetConstrainedStorageSize(gsf, &n));
45405f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetGlobalSection(dmCoarse, &gsc));
45415f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSectionGetConstrainedStorageSize(gsc, &m));
45420a96aa3bSJed Brown 
45435f80ce2aSJacob Faibussowitsch   CHKERRQ(MatCreate(PetscObjectComm((PetscObject) dmFine), injection));
45445f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
45455f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetType(*injection, MATAIJ));
45460a96aa3bSJed Brown 
45475f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoarseDM(dmFine, &cdm));
45482c71b3e2SJacob Faibussowitsch   PetscCheckFalse(cdm != dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only injection to coarse DM for now");
45490a96aa3bSJed Brown 
45500a96aa3bSJed Brown   {
45510a96aa3bSJed Brown     DM       plexF, plexC;
45520a96aa3bSJed Brown     PetscSF  sf;
45530a96aa3bSJed Brown     PetscInt *cids;
45540a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
45550a96aa3bSJed Brown 
45565f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetPlex(dmCoarse,&plexC));
45575f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetPlex(dmFine,&plexF));
45585f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
45595f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetUp(sf));
45605f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
45615f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&sf));
45625f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(cids));
45630a96aa3bSJed Brown   }
45645f80ce2aSJacob Faibussowitsch   CHKERRQ(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
45650a96aa3bSJed Brown   /* Use naive scaling */
45660a96aa3bSJed Brown   PetscFunctionReturn(0);
45670a96aa3bSJed Brown }
45680a96aa3bSJed Brown 
45690a96aa3bSJed Brown #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
45700a96aa3bSJed Brown static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
45710a96aa3bSJed Brown {
45720a96aa3bSJed Brown   DM             dmIn, dmVecIn, base, basec, plex, coarseDM;
45730a96aa3bSJed Brown   DM             *hierarchy;
45740a96aa3bSJed Brown   PetscSF        sfRed = NULL;
45750a96aa3bSJed Brown   PetscDS        ds;
45760a96aa3bSJed Brown   Vec            vecInLocal, vecOutLocal;
45770a96aa3bSJed Brown   DMLabel        subpointMap;
45780a96aa3bSJed Brown   PetscInt       minLevel, mh, n_hi, i;
45790a96aa3bSJed Brown   PetscBool      hiforest, *hierarchy_forest;
45800a96aa3bSJed Brown 
45810a96aa3bSJed Brown   PetscFunctionBegin;
45825f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetDM(vecIn,&dmVecIn));
45835f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDS(dmVecIn,&ds));
4584*28b400f6SJacob Faibussowitsch   PetscCheck(ds,PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Cannot transfer without a PetscDS object");
45850a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
45860a96aa3bSJed Brown     PetscSection section;
45870a96aa3bSJed Brown     PetscInt     Nf;
45880a96aa3bSJed Brown 
45895f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLocalSection(dmVecIn,&section));
45905f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionGetNumFields(section,&Nf));
45912c71b3e2SJacob Faibussowitsch     PetscCheckFalse(Nf > 3,PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Number of fields %D are currently not supported! Send an email at petsc-dev@mcs.anl.gov",Nf);
45920a96aa3bSJed Brown   }
45935f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetMinimumRefinement(dm,&minLevel));
4594*28b400f6SJacob Faibussowitsch   PetscCheck(!minLevel,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Cannot transfer with minimum refinement set to %D. Rerun with DMForestSetMinimumRefinement(dm,0)",minLevel);
45955f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetBaseDM(dm,&base));
4596*28b400f6SJacob Faibussowitsch   PetscCheck(base,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing base DM");
45970a96aa3bSJed Brown 
45985f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSet(vecOut,0.0));
45990a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
46005f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)vecIn));
46010a96aa3bSJed Brown   } else {
46020a96aa3bSJed Brown     PetscSection secIn, secInRed;
46030a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
46040a96aa3bSJed Brown 
46055f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectQuery((PetscObject)base,"_base_migration_sf",(PetscObject*)&sfRed));
4606*28b400f6SJacob Faibussowitsch     PetscCheck(sfRed,PETSC_COMM_SELF,PETSC_ERR_SUP,"Not the DM set with DMForestSetBaseDM()");
46075f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn),&secInRed));
46085f80ce2aSJacob Faibussowitsch     CHKERRQ(VecCreate(PETSC_COMM_SELF,&vecInRed));
46095f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLocalSection(dmVecIn,&secIn));
46105f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLocalVector(dmVecIn,&vecInLocal));
46115f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGlobalToLocalBegin(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
46125f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGlobalToLocalEnd(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
46135f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexDistributeField(dmVecIn,sfRed,secIn,vecInLocal,secInRed,vecInRed));
46145f80ce2aSJacob Faibussowitsch     CHKERRQ(DMRestoreLocalVector(dmVecIn,&vecInLocal));
46155f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&secInRed));
46160a96aa3bSJed Brown     vecIn = vecInRed;
46170a96aa3bSJed Brown   }
46180a96aa3bSJed Brown 
46190a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
46200a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
46210a96aa3bSJed Brown   hiforest = PETSC_TRUE;
46220a96aa3bSJed Brown 
46230a96aa3bSJed Brown   /* upsweep to the coarsest DM */
46240a96aa3bSJed Brown   n_hi = 0;
46250a96aa3bSJed Brown   coarseDM = dm;
46260a96aa3bSJed Brown   do {
46270a96aa3bSJed Brown     PetscBool isforest;
46280a96aa3bSJed Brown 
46290a96aa3bSJed Brown     dmIn = coarseDM;
46300a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
46315f80ce2aSJacob Faibussowitsch     CHKERRQ(DMSetUp(dmIn));
46325f80ce2aSJacob Faibussowitsch     CHKERRQ(DMIsForest(dmIn,&isforest));
4633*28b400f6SJacob Faibussowitsch     PetscCheck(isforest,PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Cannot currently transfer through a mixed hierarchy! Found DM type %s",((PetscObject)dmIn)->type_name);
46340a96aa3bSJed Brown     coarseDM = NULL;
46350a96aa3bSJed Brown     if (hiforest) {
46365f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestGetAdaptivityForest(dmIn,&coarseDM));
46370a96aa3bSJed Brown     }
46380a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
46390a96aa3bSJed Brown       hiforest = PETSC_FALSE;
46405f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoarseDM(dmIn,&coarseDM));
46410a96aa3bSJed Brown     }
46420a96aa3bSJed Brown     n_hi++;
46430a96aa3bSJed Brown   } while (coarseDM);
46440a96aa3bSJed Brown 
46455f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscMalloc2(n_hi,&hierarchy,n_hi,&hierarchy_forest));
46460a96aa3bSJed Brown 
46470a96aa3bSJed Brown   i = 0;
46480a96aa3bSJed Brown   hiforest = PETSC_TRUE;
46490a96aa3bSJed Brown   coarseDM = dm;
46500a96aa3bSJed Brown   do {
46510a96aa3bSJed Brown     dmIn = coarseDM;
46520a96aa3bSJed Brown     coarseDM = NULL;
46530a96aa3bSJed Brown     if (hiforest) {
46545f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestGetAdaptivityForest(dmIn,&coarseDM));
46550a96aa3bSJed Brown     }
46560a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
46570a96aa3bSJed Brown       hiforest = PETSC_FALSE;
46585f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetCoarseDM(dmIn,&coarseDM));
46590a96aa3bSJed Brown     }
46600a96aa3bSJed Brown     i++;
46610a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
46620a96aa3bSJed Brown   } while (coarseDM);
46630a96aa3bSJed Brown 
46640a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
46655f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dmIn,&plex));
46660a96aa3bSJed Brown 
46670a96aa3bSJed Brown   /* Check this plex is compatible with the base */
46680a96aa3bSJed Brown   {
46690a96aa3bSJed Brown     IS       gnum[2];
46700a96aa3bSJed Brown     PetscInt ncells[2],gncells[2];
46710a96aa3bSJed Brown 
46725f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCellNumbering(base,&gnum[0]));
46735f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetCellNumbering(plex,&gnum[1]));
46745f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetMinMax(gnum[0],NULL,&ncells[0]));
46755f80ce2aSJacob Faibussowitsch     CHKERRQ(ISGetMinMax(gnum[1],NULL,&ncells[1]));
46765f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPIU_Allreduce(ncells,gncells,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
46772c71b3e2SJacob Faibussowitsch     PetscCheckFalse(gncells[0] != gncells[1],PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Invalid number of base cells! Expected %D, found %D",gncells[0]+1,gncells[1]+1);
46780a96aa3bSJed Brown   }
46790a96aa3bSJed Brown 
46805f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLabel(dmIn,"_forest_base_subpoint_map",&subpointMap));
4681*28b400f6SJacob Faibussowitsch   PetscCheck(subpointMap,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing _forest_base_subpoint_map label");
46820a96aa3bSJed Brown 
46835f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexGetMaxProjectionHeight(base,&mh));
46845f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexSetMaxProjectionHeight(plex,mh));
46850a96aa3bSJed Brown 
46865f80ce2aSJacob Faibussowitsch   CHKERRQ(DMClone(base,&basec));
46875f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCopyDisc(dmVecIn,basec));
46880a96aa3bSJed Brown   if (sfRed) {
46895f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectReference((PetscObject)vecIn));
46900a96aa3bSJed Brown     vecInLocal = vecIn;
46910a96aa3bSJed Brown   } else {
46925f80ce2aSJacob Faibussowitsch     CHKERRQ(DMCreateLocalVector(basec,&vecInLocal));
46935f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGlobalToLocalBegin(basec,vecIn,INSERT_VALUES,vecInLocal));
46945f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGlobalToLocalEnd(basec,vecIn,INSERT_VALUES,vecInLocal));
46950a96aa3bSJed Brown   }
46960a96aa3bSJed Brown 
46975f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalVector(dmIn,&vecOutLocal));
46980a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
46990a96aa3bSJed Brown     PetscSF            basetocoarse;
47000a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
47010a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
47020a96aa3bSJed Brown     PetscMPIInt        rank;
47030a96aa3bSJed Brown     PetscSFNode       *remotes;
47040a96aa3bSJed Brown     PetscSection       secIn, secOut;
47050a96aa3bSJed Brown     PetscInt          *remoteOffsets;
47060a96aa3bSJed Brown     PetscSF            transferSF;
47070a96aa3bSJed Brown     const PetscScalar *inArray;
47080a96aa3bSJed Brown     PetscScalar       *outArray;
47090a96aa3bSJed Brown 
47105f80ce2aSJacob Faibussowitsch     CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
47115f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetChart(basec, &bStart, &bEnd));
47120a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
47135f80ce2aSJacob Faibussowitsch     CHKERRQ(DMPlexGetChart(plex, &iStart, &iEnd));
47140a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
47150a96aa3bSJed Brown 
47165f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(nleaves, &remotes));
47170a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
47180a96aa3bSJed Brown       PetscInt index;
47190a96aa3bSJed Brown 
47200a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
47215f80ce2aSJacob Faibussowitsch       CHKERRQ(DMLabelGetValue(subpointMap, leaf, &index));
47220a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
47230a96aa3bSJed Brown     }
47240a96aa3bSJed Brown 
47255f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
47265f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
47275f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFSetUp(basetocoarse));
47285f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetLocalSection(basec,&secIn));
47295f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn),&secOut));
47305f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
47315f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
47325f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree(remoteOffsets));
47335f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArrayWrite(vecOutLocal, &outArray));
47345f80ce2aSJacob Faibussowitsch     CHKERRQ(VecGetArrayRead(vecInLocal, &inArray));
47355f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
47365f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
47375f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArrayRead(vecInLocal, &inArray));
47385f80ce2aSJacob Faibussowitsch     CHKERRQ(VecRestoreArrayWrite(vecOutLocal, &outArray));
47395f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&transferSF));
47405f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSectionDestroy(&secOut));
47415f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscSFDestroy(&basetocoarse));
47420a96aa3bSJed Brown   }
47435f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&vecInLocal));
47445f80ce2aSJacob Faibussowitsch   CHKERRQ(DMDestroy(&basec));
47455f80ce2aSJacob Faibussowitsch   CHKERRQ(VecDestroy(&vecIn));
47460a96aa3bSJed Brown 
47470a96aa3bSJed Brown   /* output */
47480a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
47490a96aa3bSJed Brown     Vec vecOut1, vecOut2;
47500a96aa3bSJed Brown     DM  fineDM;
47510a96aa3bSJed Brown 
47525f80ce2aSJacob Faibussowitsch     CHKERRQ(DMGetGlobalVector(dmIn,&vecOut1));
47535f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut1));
47545f80ce2aSJacob Faibussowitsch     CHKERRQ(DMRestoreLocalVector(dmIn,&vecOutLocal));
47550a96aa3bSJed Brown     for (i = 1; i < n_hi-1; i++) {
47560a96aa3bSJed Brown       fineDM  = hierarchy[i];
47575f80ce2aSJacob Faibussowitsch       CHKERRQ(DMGetGlobalVector(fineDM,&vecOut2));
47585f80ce2aSJacob Faibussowitsch       CHKERRQ(DMForestTransferVec(dmIn,vecOut1,fineDM,vecOut2,PETSC_TRUE,0.0));
47595f80ce2aSJacob Faibussowitsch       CHKERRQ(DMRestoreGlobalVector(dmIn,&vecOut1));
47600a96aa3bSJed Brown       vecOut1 = vecOut2;
47610a96aa3bSJed Brown       dmIn    = fineDM;
47620a96aa3bSJed Brown     }
47635f80ce2aSJacob Faibussowitsch     CHKERRQ(DMForestTransferVec(dmIn,vecOut1,dm,vecOut,PETSC_TRUE,0.0));
47645f80ce2aSJacob Faibussowitsch     CHKERRQ(DMRestoreGlobalVector(dmIn,&vecOut1));
47650a96aa3bSJed Brown   } else {
47665f80ce2aSJacob Faibussowitsch     CHKERRQ(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut));
47675f80ce2aSJacob Faibussowitsch     CHKERRQ(DMRestoreLocalVector(dmIn,&vecOutLocal));
47680a96aa3bSJed Brown   }
47695f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree2(hierarchy,hierarchy_forest));
47700a96aa3bSJed Brown   PetscFunctionReturn(0);
47710a96aa3bSJed Brown }
47720a96aa3bSJed Brown 
47730a96aa3bSJed Brown #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
47740a96aa3bSJed Brown static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
47750a96aa3bSJed Brown {
47760a96aa3bSJed Brown   DM             adaptIn, adaptOut, plexIn, plexOut;
47770a96aa3bSJed Brown   DM_Forest      *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
47780a96aa3bSJed Brown   PetscInt       dofPerDim[] = {1, 1, 1, 1};
47790a96aa3bSJed Brown   PetscSF        inSF = NULL, outSF = NULL;
47800a96aa3bSJed Brown   PetscInt       *inCids = NULL, *outCids = NULL;
47810a96aa3bSJed Brown   DMAdaptFlag    purposeIn, purposeOut;
47820a96aa3bSJed Brown 
47830a96aa3bSJed Brown   PetscFunctionBegin;
47840a96aa3bSJed Brown   forestOut = (DM_Forest *) dmOut->data;
47850a96aa3bSJed Brown   forestIn  = (DM_Forest *) dmIn->data;
47860a96aa3bSJed Brown 
47875f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetAdaptivityForest(dmOut,&adaptOut));
47885f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetAdaptivityPurpose(dmOut,&purposeOut));
47890a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *) adaptOut->data : NULL;
47900a96aa3bSJed Brown 
47915f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetAdaptivityForest(dmIn,&adaptIn));
47925f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetAdaptivityPurpose(dmIn,&purposeIn));
47930a96aa3bSJed Brown   forestAdaptIn  = adaptIn ? (DM_Forest *) adaptIn->data : NULL;
47940a96aa3bSJed Brown 
47950a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
47960a96aa3bSJed Brown     switch (purposeOut) {
47970a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47985f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
47995f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetUp(inSF));
48000a96aa3bSJed Brown       break;
48010a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
48020a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
48035f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&outCids));
48045f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetUp(outSF));
48050a96aa3bSJed Brown       break;
48060a96aa3bSJed Brown     default:
48075f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48085f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
48095f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetUp(inSF));
48105f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetUp(outSF));
48110a96aa3bSJed Brown     }
48120a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
48130a96aa3bSJed Brown     switch (purposeIn) {
48140a96aa3bSJed Brown     case DM_ADAPT_REFINE:
48155f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&inCids));
48165f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetUp(outSF));
48170a96aa3bSJed Brown       break;
48180a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
48190a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
48205f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48215f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetUp(inSF));
48220a96aa3bSJed Brown       break;
48230a96aa3bSJed Brown     default:
48245f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48255f80ce2aSJacob Faibussowitsch       CHKERRQ(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
48265f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetUp(inSF));
48275f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscSFSetUp(outSF));
48280a96aa3bSJed Brown     }
48290a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Only support transfer from pre-adaptivity to post-adaptivity right now");
48305f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dmIn,&plexIn));
48315f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dmOut,&plexOut));
48320a96aa3bSJed Brown 
48335f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPlexTransferVecTree(plexIn,vecIn,plexOut,vecOut,inSF,outSF,inCids,outCids,useBCs,time));
48345f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(inCids));
48355f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(outCids));
48365f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFDestroy(&inSF));
48375f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFDestroy(&outSF));
48385f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(inCids));
48395f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscFree(outCids));
48400a96aa3bSJed Brown   PetscFunctionReturn(0);
48410a96aa3bSJed Brown }
48420a96aa3bSJed Brown 
48430a96aa3bSJed Brown #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
48440a96aa3bSJed Brown static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm,DM *cdm)
48450a96aa3bSJed Brown {
48460a96aa3bSJed Brown   DM             plex;
48470a96aa3bSJed Brown 
48480a96aa3bSJed Brown   PetscFunctionBegin;
48490a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
48505f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
48515f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetCoordinateDM(plex,cdm));
48525f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectReference((PetscObject)*cdm));
48530a96aa3bSJed Brown   PetscFunctionReturn(0);
48540a96aa3bSJed Brown }
48550a96aa3bSJed Brown 
48560a96aa3bSJed Brown #define VecViewLocal_pforest _append_pforest(VecViewLocal)
48570a96aa3bSJed Brown static PetscErrorCode VecViewLocal_pforest(Vec vec,PetscViewer viewer)
48580a96aa3bSJed Brown {
48590a96aa3bSJed Brown   DM             dm, plex;
48600a96aa3bSJed Brown 
48610a96aa3bSJed Brown   PetscFunctionBegin;
48625f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetDM(vec,&dm));
48635f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
48645f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,plex));
48655f80ce2aSJacob Faibussowitsch   CHKERRQ(VecView_Plex_Local(vec,viewer));
48665f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,dm));
48670a96aa3bSJed Brown   PetscFunctionReturn(0);
48680a96aa3bSJed Brown }
48690a96aa3bSJed Brown 
48700a96aa3bSJed Brown #define VecView_pforest _append_pforest(VecView)
48710a96aa3bSJed Brown static PetscErrorCode VecView_pforest(Vec vec,PetscViewer viewer)
48720a96aa3bSJed Brown {
48730a96aa3bSJed Brown   DM             dm, plex;
48740a96aa3bSJed Brown 
48750a96aa3bSJed Brown   PetscFunctionBegin;
48765f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetDM(vec,&dm));
48775f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
48785f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,plex));
48795f80ce2aSJacob Faibussowitsch   CHKERRQ(VecView_Plex(vec,viewer));
48805f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,dm));
48810a96aa3bSJed Brown   PetscFunctionReturn(0);
48820a96aa3bSJed Brown }
48830a96aa3bSJed Brown 
48840a96aa3bSJed Brown #define VecView_pforest_Native _infix_pforest(VecView,_Native)
48850a96aa3bSJed Brown static PetscErrorCode VecView_pforest_Native(Vec vec,PetscViewer viewer)
48860a96aa3bSJed Brown {
48870a96aa3bSJed Brown   DM             dm, plex;
48880a96aa3bSJed Brown 
48890a96aa3bSJed Brown   PetscFunctionBegin;
48905f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetDM(vec,&dm));
48915f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
48925f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,plex));
48935f80ce2aSJacob Faibussowitsch   CHKERRQ(VecView_Plex_Native(vec,viewer));
48945f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,dm));
48950a96aa3bSJed Brown   PetscFunctionReturn(0);
48960a96aa3bSJed Brown }
48970a96aa3bSJed Brown 
48980a96aa3bSJed Brown #define VecLoad_pforest _append_pforest(VecLoad)
48990a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest(Vec vec,PetscViewer viewer)
49000a96aa3bSJed Brown {
49010a96aa3bSJed Brown   DM             dm, plex;
49020a96aa3bSJed Brown 
49030a96aa3bSJed Brown   PetscFunctionBegin;
49045f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetDM(vec,&dm));
49055f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
49065f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,plex));
49075f80ce2aSJacob Faibussowitsch   CHKERRQ(VecLoad_Plex(vec,viewer));
49085f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,dm));
49090a96aa3bSJed Brown   PetscFunctionReturn(0);
49100a96aa3bSJed Brown }
49110a96aa3bSJed Brown 
49120a96aa3bSJed Brown #define VecLoad_pforest_Native _infix_pforest(VecLoad,_Native)
49130a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest_Native(Vec vec,PetscViewer viewer)
49140a96aa3bSJed Brown {
49150a96aa3bSJed Brown   DM             dm, plex;
49160a96aa3bSJed Brown 
49170a96aa3bSJed Brown   PetscFunctionBegin;
49185f80ce2aSJacob Faibussowitsch   CHKERRQ(VecGetDM(vec,&dm));
49195f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
49205f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,plex));
49215f80ce2aSJacob Faibussowitsch   CHKERRQ(VecLoad_Plex_Native(vec,viewer));
49225f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetDM(vec,dm));
49230a96aa3bSJed Brown   PetscFunctionReturn(0);
49240a96aa3bSJed Brown }
49250a96aa3bSJed Brown 
49260a96aa3bSJed Brown #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
49270a96aa3bSJed Brown static PetscErrorCode DMCreateGlobalVector_pforest(DM dm,Vec *vec)
49280a96aa3bSJed Brown {
49290a96aa3bSJed Brown   PetscFunctionBegin;
49305f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateGlobalVector_Section_Private(dm,vec));
49315f80ce2aSJacob Faibussowitsch   /* CHKERRQ(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
49325f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
49335f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
49345f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
49355f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
49360a96aa3bSJed Brown   PetscFunctionReturn(0);
49370a96aa3bSJed Brown }
49380a96aa3bSJed Brown 
49390a96aa3bSJed Brown #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
49400a96aa3bSJed Brown static PetscErrorCode DMCreateLocalVector_pforest(DM dm,Vec *vec)
49410a96aa3bSJed Brown {
49420a96aa3bSJed Brown   PetscFunctionBegin;
49435f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateLocalVector_Section_Private(dm,vec));
49445f80ce2aSJacob Faibussowitsch   CHKERRQ(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
49450a96aa3bSJed Brown   PetscFunctionReturn(0);
49460a96aa3bSJed Brown }
49470a96aa3bSJed Brown 
49480a96aa3bSJed Brown #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
49490a96aa3bSJed Brown static PetscErrorCode DMCreateMatrix_pforest(DM dm,Mat *mat)
49500a96aa3bSJed Brown {
49510a96aa3bSJed Brown   DM             plex;
49520a96aa3bSJed Brown 
49530a96aa3bSJed Brown   PetscFunctionBegin;
49540a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49555f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
49560a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only;  /* maybe this should go into forest->plex */
49575f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateMatrix(plex,mat));
49585f80ce2aSJacob Faibussowitsch   CHKERRQ(MatSetDM(*mat,dm));
49590a96aa3bSJed Brown   PetscFunctionReturn(0);
49600a96aa3bSJed Brown }
49610a96aa3bSJed Brown 
49620a96aa3bSJed Brown #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
49630a96aa3bSJed Brown static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, InsertMode mode, Vec localX)
49640a96aa3bSJed Brown {
49650a96aa3bSJed Brown   DM             plex;
49660a96aa3bSJed Brown 
49670a96aa3bSJed Brown   PetscFunctionBegin;
49680a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49695f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
49705f80ce2aSJacob Faibussowitsch   CHKERRQ(DMProjectFunctionLocal(plex,time,funcs,ctxs,mode,localX));
49710a96aa3bSJed Brown   PetscFunctionReturn(0);
49720a96aa3bSJed Brown }
49730a96aa3bSJed Brown 
49740a96aa3bSJed Brown #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
49750a96aa3bSJed 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)
49760a96aa3bSJed Brown {
49770a96aa3bSJed Brown   DM             plex;
49780a96aa3bSJed Brown 
49790a96aa3bSJed Brown   PetscFunctionBegin;
49800a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49815f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
49825f80ce2aSJacob Faibussowitsch   CHKERRQ(DMProjectFunctionLabelLocal(plex,time,label,numIds,ids,Ncc,comps,funcs,ctxs,mode,localX));
49830a96aa3bSJed Brown   PetscFunctionReturn(0);
49840a96aa3bSJed Brown }
49850a96aa3bSJed Brown 
49860a96aa3bSJed Brown #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
49870a96aa3bSJed Brown PetscErrorCode DMProjectFieldLocal_pforest(DM dm, PetscReal time, Vec localU,void (**funcs) (PetscInt, PetscInt, PetscInt,
49880a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
49890a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
49900a96aa3bSJed Brown                                                                              PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),InsertMode mode, Vec localX)
49910a96aa3bSJed Brown {
49920a96aa3bSJed Brown   DM             plex;
49930a96aa3bSJed Brown 
49940a96aa3bSJed Brown   PetscFunctionBegin;
49950a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49965f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
49975f80ce2aSJacob Faibussowitsch   CHKERRQ(DMProjectFieldLocal(plex,time,localU,funcs,mode,localX));
49980a96aa3bSJed Brown   PetscFunctionReturn(0);
49990a96aa3bSJed Brown }
50000a96aa3bSJed Brown 
50010a96aa3bSJed Brown #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
50020a96aa3bSJed Brown PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal *diff)
50030a96aa3bSJed Brown {
50040a96aa3bSJed Brown   DM             plex;
50050a96aa3bSJed Brown 
50060a96aa3bSJed Brown   PetscFunctionBegin;
50070a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50085f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
50095f80ce2aSJacob Faibussowitsch   CHKERRQ(DMComputeL2Diff(plex,time,funcs,ctxs,X,diff));
50100a96aa3bSJed Brown   PetscFunctionReturn(0);
50110a96aa3bSJed Brown }
50120a96aa3bSJed Brown 
50130a96aa3bSJed Brown #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
50140a96aa3bSJed Brown PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal diff[])
50150a96aa3bSJed Brown {
50160a96aa3bSJed Brown   DM             plex;
50170a96aa3bSJed Brown 
50180a96aa3bSJed Brown   PetscFunctionBegin;
50190a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50205f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
50215f80ce2aSJacob Faibussowitsch   CHKERRQ(DMComputeL2FieldDiff(plex,time,funcs,ctxs,X,diff));
50220a96aa3bSJed Brown   PetscFunctionReturn(0);
50230a96aa3bSJed Brown }
50240a96aa3bSJed Brown 
50250a96aa3bSJed Brown #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
50260a96aa3bSJed Brown static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
50270a96aa3bSJed Brown {
50280a96aa3bSJed Brown   DM             plex;
50290a96aa3bSJed Brown   PetscSection   section;
50300a96aa3bSJed Brown 
50310a96aa3bSJed Brown   PetscFunctionBegin;
50320a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50335f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
50345f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetLocalSection(plex,&section));
50355f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetLocalSection(dm,section));
50360a96aa3bSJed Brown   PetscFunctionReturn(0);
50370a96aa3bSJed Brown }
50380a96aa3bSJed Brown 
50390a96aa3bSJed Brown #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
50400a96aa3bSJed Brown static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
50410a96aa3bSJed Brown {
50420a96aa3bSJed Brown   DM             plex;
50430a96aa3bSJed Brown   Mat            mat;
504479769bd5SJed Brown   Vec            bias;
50450a96aa3bSJed Brown   PetscSection   section;
50460a96aa3bSJed Brown 
50470a96aa3bSJed Brown   PetscFunctionBegin;
50480a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50495f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
50505f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDefaultConstraints(plex,&section,&mat,&bias));
50515f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetDefaultConstraints(dm,section,mat,bias));
50520a96aa3bSJed Brown   PetscFunctionReturn(0);
50530a96aa3bSJed Brown }
50540a96aa3bSJed Brown 
50550a96aa3bSJed Brown #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
50560a96aa3bSJed Brown static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
50570a96aa3bSJed Brown {
50580a96aa3bSJed Brown   DM             plex;
50590a96aa3bSJed Brown 
50600a96aa3bSJed Brown   PetscFunctionBegin;
50610a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50625f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
50635f80ce2aSJacob Faibussowitsch   CHKERRQ(DMGetDimPoints(plex,dim,cStart,cEnd));
50640a96aa3bSJed Brown   PetscFunctionReturn(0);
50650a96aa3bSJed Brown }
50660a96aa3bSJed Brown 
50670a96aa3bSJed Brown /* Need to forward declare */
50680a96aa3bSJed Brown #define DMInitialize_pforest _append_pforest(DMInitialize)
50690a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
50700a96aa3bSJed Brown 
50710a96aa3bSJed Brown #define DMClone_pforest _append_pforest(DMClone)
50720a96aa3bSJed Brown static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
50730a96aa3bSJed Brown {
50740a96aa3bSJed Brown   PetscFunctionBegin;
50755f80ce2aSJacob Faibussowitsch   CHKERRQ(DMClone_Forest(dm,newdm));
50765f80ce2aSJacob Faibussowitsch   CHKERRQ(DMInitialize_pforest(*newdm));
50770a96aa3bSJed Brown   PetscFunctionReturn(0);
50780a96aa3bSJed Brown }
50790a96aa3bSJed Brown 
50800a96aa3bSJed Brown #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
50810a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
50820a96aa3bSJed Brown {
50830a96aa3bSJed Brown   DM_Forest         *forest;
50840a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50850a96aa3bSJed Brown   PetscInt          overlap;
50860a96aa3bSJed Brown 
50870a96aa3bSJed Brown   PetscFunctionBegin;
50885f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetUp(dm));
50890a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
50900a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
50910a96aa3bSJed Brown   *cStart = 0;
50925f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetPartitionOverlap(dm,&overlap));
50930a96aa3bSJed Brown   if (overlap && pforest->ghost) {
50940a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
50950a96aa3bSJed Brown   } else {
50960a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
50970a96aa3bSJed Brown   }
50980a96aa3bSJed Brown   PetscFunctionReturn(0);
50990a96aa3bSJed Brown }
51000a96aa3bSJed Brown 
51010a96aa3bSJed Brown #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
51020a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
51030a96aa3bSJed Brown {
51040a96aa3bSJed Brown   DM_Forest         *forest;
51050a96aa3bSJed Brown   DM_Forest_pforest *pforest;
51060a96aa3bSJed Brown   PetscMPIInt       rank;
51070a96aa3bSJed Brown   PetscInt          overlap;
51080a96aa3bSJed Brown   PetscInt          cStart, cEnd, cLocalStart, cLocalEnd;
51090a96aa3bSJed Brown   PetscInt          nRoots, nLeaves, *mine = NULL;
51100a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
51110a96aa3bSJed Brown   PetscSF           sf;
51120a96aa3bSJed Brown 
51130a96aa3bSJed Brown   PetscFunctionBegin;
51145f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetCellChart(dm,&cStart,&cEnd));
51150a96aa3bSJed Brown   forest      = (DM_Forest*)         dm->data;
51160a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
51170a96aa3bSJed Brown   nRoots      = cEnd - cStart;
51180a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
51190a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
51200a96aa3bSJed Brown   nLeaves     = 0;
51215f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestGetPartitionOverlap(dm,&overlap));
51225f80ce2aSJacob Faibussowitsch   CHKERRMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
51230a96aa3bSJed Brown   if (overlap && pforest->ghost) {
51240a96aa3bSJed Brown     PetscSFNode      *mirror;
51250a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
51260a96aa3bSJed Brown     PetscInt         nMirror, nGhostPre, nSelf, q;
51270a96aa3bSJed Brown     void             **mirrorPtrs;
51280a96aa3bSJed Brown 
51290a96aa3bSJed Brown     nMirror      = (PetscInt) pforest->ghost->mirrors.elem_count;
51300a96aa3bSJed Brown     nSelf        = cLocalEnd - cLocalStart;
51310a96aa3bSJed Brown     nLeaves      = nRoots - nSelf;
51320a96aa3bSJed Brown     nGhostPre    = (PetscInt) pforest->ghost->proc_offsets[rank];
51335f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(nLeaves,&mine));
51345f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc1(nLeaves,&remote));
51355f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscMalloc2(nMirror,&mirror,nMirror,&mirrorPtrs));
51360a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t*) pforest->ghost->mirrors.array;
51370a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
51380a96aa3bSJed Brown       p4est_quadrant_t *mir = &(mirror_array[q]);
51390a96aa3bSJed Brown 
51400a96aa3bSJed Brown       mirror[q].rank  = rank;
51410a96aa3bSJed Brown       mirror[q].index = (PetscInt) mir->p.piggy3.local_num + cLocalStart;
51420a96aa3bSJed Brown       mirrorPtrs[q]   = (void*) &(mirror[q]);
51430a96aa3bSJed Brown     }
51440a96aa3bSJed Brown     PetscStackCallP4est(p4est_ghost_exchange_custom,(pforest->forest,pforest->ghost,sizeof(PetscSFNode),mirrorPtrs,remote));
51455f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscFree2(mirror,mirrorPtrs));
51460a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
51470a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
51480a96aa3bSJed Brown   }
51495f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFCreate(PetscObjectComm((PetscObject)dm),&sf));
51505f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscSFSetGraph(sf,nRoots,nLeaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
51510a96aa3bSJed Brown   *cellSF = sf;
51520a96aa3bSJed Brown   PetscFunctionReturn(0);
51530a96aa3bSJed Brown }
51540a96aa3bSJed Brown 
51550a96aa3bSJed Brown static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS* ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void*), void **setup_ctx)
51560a96aa3bSJed Brown {
51570a96aa3bSJed Brown   DM             plex;
51580a96aa3bSJed Brown 
51590a96aa3bSJed Brown   PetscFunctionBegin;
51605f80ce2aSJacob Faibussowitsch   CHKERRQ(DMPforestGetPlex(dm,&plex));
51615f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreateNeumannOverlap_Plex(plex,ovl,J,setup,setup_ctx));
51620a96aa3bSJed Brown   if (!*setup) {
51635f80ce2aSJacob Faibussowitsch     CHKERRQ(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
51640a96aa3bSJed Brown     if (*setup) {
51655f80ce2aSJacob Faibussowitsch       CHKERRQ(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
51660a96aa3bSJed Brown     }
51670a96aa3bSJed Brown   }
51680a96aa3bSJed Brown   PetscFunctionReturn(0);
51690a96aa3bSJed Brown }
51700a96aa3bSJed Brown 
51710a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm)
51720a96aa3bSJed Brown {
51730a96aa3bSJed Brown   PetscFunctionBegin;
51740a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
51750a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
51760a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
51770a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
51780a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
51790a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
51800a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
51810a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
51820a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
51830a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
51840a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
51850a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
51860a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
51870a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
51880a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
51890a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
51900a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
51910a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
51920a96aa3bSJed Brown 
51935f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",DMConvert_plex_pforest));
51945f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",DMConvert_pforest_plex));
51955f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_pforest));
51965f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMForestGetPartitionOverlap));
51970a96aa3bSJed Brown   PetscFunctionReturn(0);
51980a96aa3bSJed Brown }
51990a96aa3bSJed Brown 
52000a96aa3bSJed Brown #define DMCreate_pforest _append_pforest(DMCreate)
52010a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
52020a96aa3bSJed Brown {
52030a96aa3bSJed Brown   DM_Forest         *forest;
52040a96aa3bSJed Brown   DM_Forest_pforest *pforest;
52050a96aa3bSJed Brown 
52060a96aa3bSJed Brown   PetscFunctionBegin;
52075f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscP4estInitialize());
52085f80ce2aSJacob Faibussowitsch   CHKERRQ(DMCreate_Forest(dm));
52095f80ce2aSJacob Faibussowitsch   CHKERRQ(DMInitialize_pforest(dm));
52105f80ce2aSJacob Faibussowitsch   CHKERRQ(DMSetDimension(dm,P4EST_DIM));
52110a96aa3bSJed Brown 
52120a96aa3bSJed Brown   /* set forest defaults */
52135f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestSetTopology(dm,"unit"));
52145f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestSetMinimumRefinement(dm,0));
52155f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestSetInitialRefinement(dm,0));
52165f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestSetMaximumRefinement(dm,P4EST_QMAXLEVEL));
52175f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestSetGradeFactor(dm,2));
52185f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestSetAdjacencyDimension(dm,0));
52195f80ce2aSJacob Faibussowitsch   CHKERRQ(DMForestSetPartitionOverlap(dm,0));
52200a96aa3bSJed Brown 
52210a96aa3bSJed Brown   /* create p4est data */
52225f80ce2aSJacob Faibussowitsch   CHKERRQ(PetscNewLog(dm,&pforest));
52230a96aa3bSJed Brown 
52240a96aa3bSJed Brown   forest                            = (DM_Forest*) dm->data;
52250a96aa3bSJed Brown   forest->data                      = pforest;
52260a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
52270a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
52280a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
52290a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
52300a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
52310a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
52320a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
52330a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
52340a96aa3bSJed Brown   pforest->topo                     = NULL;
52350a96aa3bSJed Brown   pforest->forest                   = NULL;
52360a96aa3bSJed Brown   pforest->ghost                    = NULL;
52370a96aa3bSJed Brown   pforest->lnodes                   = NULL;
52380a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
52390a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
52400a96aa3bSJed Brown   pforest->cLocalStart              = -1;
52410a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
52420a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
52430a96aa3bSJed Brown   pforest->ghostName                = NULL;
52440a96aa3bSJed Brown   PetscFunctionReturn(0);
52450a96aa3bSJed Brown }
52460a96aa3bSJed Brown 
52470a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5248