xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 66c0a4b53a810490bc74e78cb9c26cce538c9fce)
10a96aa3bSJed Brown #include <petscds.h>
20a96aa3bSJed Brown #include <petsc/private/dmimpl.h>
30a96aa3bSJed Brown #include <petsc/private/dmforestimpl.h>
40a96aa3bSJed Brown #include <petsc/private/dmpleximpl.h>
50a96aa3bSJed Brown #include <petsc/private/dmlabelimpl.h>
60a96aa3bSJed Brown #include <petsc/private/viewerimpl.h>
70a96aa3bSJed Brown #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h>
80a96aa3bSJed Brown #include "petsc_p4est_package.h"
90a96aa3bSJed Brown 
100a96aa3bSJed Brown #if defined(PETSC_HAVE_P4EST)
110a96aa3bSJed Brown 
120a96aa3bSJed Brown #if !defined(P4_TO_P8)
130a96aa3bSJed Brown #include <p4est.h>
140a96aa3bSJed Brown #include <p4est_extended.h>
150a96aa3bSJed Brown #include <p4est_geometry.h>
160a96aa3bSJed Brown #include <p4est_ghost.h>
170a96aa3bSJed Brown #include <p4est_lnodes.h>
180a96aa3bSJed Brown #include <p4est_vtk.h>
190a96aa3bSJed Brown #include <p4est_plex.h>
200a96aa3bSJed Brown #include <p4est_bits.h>
210a96aa3bSJed Brown #include <p4est_algorithms.h>
220a96aa3bSJed Brown #else
230a96aa3bSJed Brown #include <p8est.h>
240a96aa3bSJed Brown #include <p8est_extended.h>
250a96aa3bSJed Brown #include <p8est_geometry.h>
260a96aa3bSJed Brown #include <p8est_ghost.h>
270a96aa3bSJed Brown #include <p8est_lnodes.h>
280a96aa3bSJed Brown #include <p8est_vtk.h>
290a96aa3bSJed Brown #include <p8est_plex.h>
300a96aa3bSJed Brown #include <p8est_bits.h>
310a96aa3bSJed Brown #include <p8est_algorithms.h>
320a96aa3bSJed Brown #endif
330a96aa3bSJed Brown 
340a96aa3bSJed Brown typedef enum {PATTERN_HASH,PATTERN_FRACTAL,PATTERN_CORNER,PATTERN_CENTER,PATTERN_COUNT} DMRefinePattern;
350a96aa3bSJed Brown static const char *DMRefinePatternName[PATTERN_COUNT] = {"hash","fractal","corner","center"};
360a96aa3bSJed Brown 
370a96aa3bSJed Brown typedef struct _DMRefinePatternCtx
380a96aa3bSJed Brown {
390a96aa3bSJed Brown   PetscInt       corner;
400a96aa3bSJed Brown   PetscBool      fractal[P4EST_CHILDREN];
410a96aa3bSJed Brown   PetscReal      hashLikelihood;
420a96aa3bSJed Brown   PetscInt       maxLevel;
430a96aa3bSJed Brown   p4est_refine_t refine_fn;
440a96aa3bSJed Brown }
450a96aa3bSJed Brown DMRefinePatternCtx;
460a96aa3bSJed Brown 
470a96aa3bSJed Brown static int DMRefinePattern_Corner(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
480a96aa3bSJed Brown {
490a96aa3bSJed Brown   p4est_quadrant_t   root, rootcorner;
500a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
510a96aa3bSJed Brown 
520a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
530a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
540a96aa3bSJed Brown 
550a96aa3bSJed Brown   root.x = root.y = 0;
560a96aa3bSJed Brown #if defined(P4_TO_P8)
570a96aa3bSJed Brown   root.z = 0;
580a96aa3bSJed Brown #endif
590a96aa3bSJed Brown   root.level = 0;
600a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&root,&rootcorner,ctx->corner,quadrant->level);
610a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant,&rootcorner)) return 1;
620a96aa3bSJed Brown   return 0;
630a96aa3bSJed Brown }
640a96aa3bSJed Brown 
650a96aa3bSJed Brown static int DMRefinePattern_Center(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
660a96aa3bSJed Brown {
670a96aa3bSJed Brown   int                cid;
680a96aa3bSJed Brown   p4est_quadrant_t   ancestor, ancestorcorner;
690a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
700a96aa3bSJed Brown 
710a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
720a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
730a96aa3bSJed Brown   if (quadrant->level <= 1) return 1;
740a96aa3bSJed Brown 
750a96aa3bSJed Brown   p4est_quadrant_ancestor(quadrant,1,&ancestor);
760a96aa3bSJed Brown   cid = p4est_quadrant_child_id(&ancestor);
770a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&ancestor,&ancestorcorner,P4EST_CHILDREN - 1 - cid,quadrant->level);
780a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant,&ancestorcorner)) return 1;
790a96aa3bSJed Brown   return 0;
800a96aa3bSJed Brown }
810a96aa3bSJed Brown 
820a96aa3bSJed Brown static int DMRefinePattern_Fractal(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
830a96aa3bSJed Brown {
840a96aa3bSJed Brown   int                cid;
850a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
860a96aa3bSJed Brown 
870a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
880a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
890a96aa3bSJed Brown   if (!quadrant->level) return 1;
900a96aa3bSJed Brown   cid = p4est_quadrant_child_id(quadrant);
910a96aa3bSJed Brown   if (ctx->fractal[cid ^ ((int) (quadrant->level % P4EST_CHILDREN))]) return 1;
920a96aa3bSJed Brown   return 0;
930a96aa3bSJed Brown }
940a96aa3bSJed Brown 
950a96aa3bSJed Brown /* simplified from MurmurHash3 by Austin Appleby */
960a96aa3bSJed Brown #define DMPROT32(x, y) ((x << y) | (x >> (32 - y)))
970a96aa3bSJed Brown static uint32_t DMPforestHash(const uint32_t *blocks, uint32_t nblocks)
980a96aa3bSJed Brown {
990a96aa3bSJed Brown   uint32_t c1   = 0xcc9e2d51;
1000a96aa3bSJed Brown   uint32_t c2   = 0x1b873593;
1010a96aa3bSJed Brown   uint32_t r1   = 15;
1020a96aa3bSJed Brown   uint32_t r2   = 13;
1030a96aa3bSJed Brown   uint32_t m    = 5;
1040a96aa3bSJed Brown   uint32_t n    = 0xe6546b64;
1050a96aa3bSJed Brown   uint32_t hash = 0;
1060a96aa3bSJed Brown   int      len  = nblocks * 4;
1070a96aa3bSJed Brown   uint32_t i;
1080a96aa3bSJed Brown 
1090a96aa3bSJed Brown   for (i = 0; i < nblocks; i++) {
1100a96aa3bSJed Brown     uint32_t k;
1110a96aa3bSJed Brown 
1120a96aa3bSJed Brown     k  = blocks[i];
1130a96aa3bSJed Brown     k *= c1;
1140a96aa3bSJed Brown     k  = DMPROT32(k, r1);
1150a96aa3bSJed Brown     k *= c2;
1160a96aa3bSJed Brown 
1170a96aa3bSJed Brown     hash ^= k;
1180a96aa3bSJed Brown     hash  = DMPROT32(hash, r2) * m + n;
1190a96aa3bSJed Brown   }
1200a96aa3bSJed Brown 
1210a96aa3bSJed Brown   hash ^= len;
1220a96aa3bSJed Brown   hash ^= (hash >> 16);
1230a96aa3bSJed Brown   hash *= 0x85ebca6b;
1240a96aa3bSJed Brown   hash ^= (hash >> 13);
1250a96aa3bSJed Brown   hash *= 0xc2b2ae35;
1260a96aa3bSJed Brown   hash ^= (hash >> 16);
1270a96aa3bSJed Brown 
1280a96aa3bSJed Brown   return hash;
1290a96aa3bSJed Brown }
1300a96aa3bSJed Brown 
1310a96aa3bSJed Brown #if defined(UINT32_MAX)
1320a96aa3bSJed Brown #define DMP4EST_HASH_MAX UINT32_MAX
1330a96aa3bSJed Brown #else
1340a96aa3bSJed Brown #define DMP4EST_HASH_MAX ((uint32_t) 0xffffffff)
1350a96aa3bSJed Brown #endif
1360a96aa3bSJed Brown 
1370a96aa3bSJed Brown static int DMRefinePattern_Hash(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
1380a96aa3bSJed Brown {
1390a96aa3bSJed Brown   uint32_t           data[5];
1400a96aa3bSJed Brown   uint32_t           result;
1410a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
1420a96aa3bSJed Brown 
1430a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
1440a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
1450a96aa3bSJed Brown   data[0] = ((uint32_t) quadrant->level) << 24;
1460a96aa3bSJed Brown   data[1] = (uint32_t) which_tree;
1470a96aa3bSJed Brown   data[2] = (uint32_t) quadrant->x;
1480a96aa3bSJed Brown   data[3] = (uint32_t) quadrant->y;
1490a96aa3bSJed Brown #if defined(P4_TO_P8)
1500a96aa3bSJed Brown   data[4] = (uint32_t) quadrant->z;
1510a96aa3bSJed Brown #endif
1520a96aa3bSJed Brown 
1530a96aa3bSJed Brown   result = DMPforestHash(data,2+P4EST_DIM);
1540a96aa3bSJed Brown   if (((double) result / (double) DMP4EST_HASH_MAX) < ctx->hashLikelihood) return 1;
1550a96aa3bSJed Brown   return 0;
1560a96aa3bSJed Brown }
1570a96aa3bSJed Brown 
1580a96aa3bSJed Brown #define DMConvert_pforest_plex _infix_pforest(DMConvert,_plex)
1590a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM,DMType,DM*);
1600a96aa3bSJed Brown 
1610a96aa3bSJed Brown #define DMFTopology_pforest _append_pforest(DMFTopology)
1620a96aa3bSJed Brown typedef struct {
1630a96aa3bSJed Brown   PetscInt             refct;
1640a96aa3bSJed Brown   p4est_connectivity_t *conn;
1650a96aa3bSJed Brown   p4est_geometry_t     *geom;
1660a96aa3bSJed Brown   PetscInt             *tree_face_to_uniq; /* p4est does not explicitly enumerate facets, but we must to keep track of labels */
1670a96aa3bSJed Brown } DMFTopology_pforest;
1680a96aa3bSJed Brown 
1690a96aa3bSJed Brown #define DM_Forest_pforest _append_pforest(DM_Forest)
1700a96aa3bSJed Brown typedef struct {
1710a96aa3bSJed Brown   DMFTopology_pforest *topo;
1720a96aa3bSJed Brown   p4est_t             *forest;
1730a96aa3bSJed Brown   p4est_ghost_t       *ghost;
1740a96aa3bSJed Brown   p4est_lnodes_t      *lnodes;
1750a96aa3bSJed Brown   PetscBool           partition_for_coarsening;
1760a96aa3bSJed Brown   PetscBool           coarsen_hierarchy;
1770a96aa3bSJed Brown   PetscBool           labelsFinalized;
1780a96aa3bSJed Brown   PetscBool           adaptivitySuccess;
1790a96aa3bSJed Brown   PetscInt            cLocalStart;
1800a96aa3bSJed Brown   PetscInt            cLocalEnd;
1810a96aa3bSJed Brown   DM                  plex;
1820a96aa3bSJed Brown   char                *ghostName;
1830a96aa3bSJed Brown   PetscSF             pointAdaptToSelfSF;
1840a96aa3bSJed Brown   PetscSF             pointSelfToAdaptSF;
1850a96aa3bSJed Brown   PetscInt            *pointAdaptToSelfCids;
1860a96aa3bSJed Brown   PetscInt            *pointSelfToAdaptCids;
1870a96aa3bSJed Brown } DM_Forest_pforest;
1880a96aa3bSJed Brown 
1890a96aa3bSJed Brown #define DM_Forest_geometry_pforest _append_pforest(DM_Forest_geometry)
1900a96aa3bSJed Brown typedef struct {
1910a96aa3bSJed Brown   DM base;
1920a96aa3bSJed Brown   PetscErrorCode   (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void*);
1930a96aa3bSJed Brown   void             *mapCtx;
1940a96aa3bSJed Brown   PetscInt         coordDim;
1950a96aa3bSJed Brown   p4est_geometry_t *inner;
1960a96aa3bSJed Brown }
1970a96aa3bSJed Brown DM_Forest_geometry_pforest;
1980a96aa3bSJed Brown 
1990a96aa3bSJed Brown #define GeometryMapping_pforest _append_pforest(GeometryMapping)
2000a96aa3bSJed Brown static void GeometryMapping_pforest(p4est_geometry_t *geom, p4est_topidx_t which_tree, const double abc[3], double xyz[3])
2010a96aa3bSJed Brown {
2020a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user;
2030a96aa3bSJed Brown   PetscReal                  PetscABC[3]   = {0.};
2040a96aa3bSJed Brown   PetscReal                  PetscXYZ[3]   = {0.};
2050a96aa3bSJed Brown   PetscInt                   i, d = PetscMin(3,geom_pforest->coordDim);
2060a96aa3bSJed Brown   double                     ABC[3];
2070a96aa3bSJed Brown   PetscErrorCode             ierr;
2080a96aa3bSJed Brown 
2090a96aa3bSJed Brown   (geom_pforest->inner->X)(geom_pforest->inner,which_tree,abc,ABC);
2100a96aa3bSJed Brown 
2110a96aa3bSJed Brown   for (i = 0; i < d; i++) PetscABC[i] = ABC[i];
2120a96aa3bSJed Brown   ierr = (geom_pforest->map)(geom_pforest->base,(PetscInt) which_tree,geom_pforest->coordDim,PetscABC,PetscXYZ,geom_pforest->mapCtx);PETSC_P4EST_ASSERT(!ierr);
2130a96aa3bSJed Brown   for (i = 0; i < d; i++) xyz[i] = PetscXYZ[i];
2140a96aa3bSJed Brown }
2150a96aa3bSJed Brown 
2160a96aa3bSJed Brown #define GeometryDestroy_pforest _append_pforest(GeometryDestroy)
2170a96aa3bSJed Brown static void GeometryDestroy_pforest(p4est_geometry_t *geom)
2180a96aa3bSJed Brown {
2190a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user;
2200a96aa3bSJed Brown   PetscErrorCode             ierr;
2210a96aa3bSJed Brown 
2220a96aa3bSJed Brown   p4est_geometry_destroy(geom_pforest->inner);
2230a96aa3bSJed Brown   ierr = PetscFree(geom->user);PETSC_P4EST_ASSERT(!ierr);
2240a96aa3bSJed Brown   ierr = PetscFree(geom);PETSC_P4EST_ASSERT(!ierr);
2250a96aa3bSJed Brown }
2260a96aa3bSJed Brown 
2270a96aa3bSJed Brown #define DMFTopologyDestroy_pforest _append_pforest(DMFTopologyDestroy)
2280a96aa3bSJed Brown static PetscErrorCode DMFTopologyDestroy_pforest(DMFTopology_pforest **topo)
2290a96aa3bSJed Brown {
2300a96aa3bSJed Brown   PetscFunctionBegin;
2310a96aa3bSJed Brown   if (!(*topo)) PetscFunctionReturn(0);
2320a96aa3bSJed Brown   if (--((*topo)->refct) > 0) {
2330a96aa3bSJed Brown     *topo = NULL;
2340a96aa3bSJed Brown     PetscFunctionReturn(0);
2350a96aa3bSJed Brown   }
2360a96aa3bSJed Brown   if ((*topo)->geom) PetscStackCallP4est(p4est_geometry_destroy,((*topo)->geom));
2370a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,((*topo)->conn));
2389566063dSJacob Faibussowitsch   PetscCall(PetscFree((*topo)->tree_face_to_uniq));
2399566063dSJacob Faibussowitsch   PetscCall(PetscFree(*topo));
2400a96aa3bSJed Brown   *topo = NULL;
2410a96aa3bSJed Brown   PetscFunctionReturn(0);
2420a96aa3bSJed Brown }
2430a96aa3bSJed Brown 
2440a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t*,PetscInt**);
2450a96aa3bSJed Brown 
2460a96aa3bSJed Brown #define DMFTopologyCreateBrick_pforest _append_pforest(DMFTopologyCreateBrick)
2470a96aa3bSJed Brown static PetscErrorCode DMFTopologyCreateBrick_pforest(DM dm,PetscInt N[], PetscInt P[], PetscReal B[],DMFTopology_pforest **topo, PetscBool useMorton)
2480a96aa3bSJed Brown {
2490a96aa3bSJed Brown   double         *vertices;
2500a96aa3bSJed Brown   PetscInt       i, numVerts;
2510a96aa3bSJed Brown 
2520a96aa3bSJed Brown   PetscFunctionBegin;
25328b400f6SJacob Faibussowitsch   PetscCheck(useMorton,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Lexicographic ordering not implemented yet");
2549566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(dm,topo));
2550a96aa3bSJed Brown 
2560a96aa3bSJed Brown   (*topo)->refct = 1;
2570a96aa3bSJed Brown #if !defined(P4_TO_P8)
2580a96aa3bSJed Brown   PetscStackCallP4estReturn((*topo)->conn,p4est_connectivity_new_brick,((int) N[0], (int) N[1], (P[0] == DM_BOUNDARY_NONE) ? 0 : 1, (P[1] == DM_BOUNDARY_NONE) ? 0 : 1));
2590a96aa3bSJed Brown #else
2600a96aa3bSJed Brown   PetscStackCallP4estReturn((*topo)->conn,p8est_connectivity_new_brick,((int) N[0], (int) N[1], (int) N[2], (P[0] == DM_BOUNDARY_NONE) ? 0 : 1, (P[1] == DM_BOUNDARY_NONE) ? 0 : 1, (P[2] == DM_BOUNDARY_NONE) ? 0 : 1));
2610a96aa3bSJed Brown #endif
2620a96aa3bSJed Brown   numVerts = (*topo)->conn->num_vertices;
2630a96aa3bSJed Brown   vertices = (*topo)->conn->vertices;
2640a96aa3bSJed Brown   for (i = 0; i < 3 * numVerts; i++) {
2650a96aa3bSJed Brown     PetscInt j = i % 3;
2660a96aa3bSJed Brown 
2670a96aa3bSJed Brown     vertices[i] = B[2 * j] + (vertices[i]/N[j]) * (B[2 * j + 1] - B[2 * j]);
2680a96aa3bSJed Brown   }
2690a96aa3bSJed Brown   (*topo)->geom = NULL;
2709566063dSJacob Faibussowitsch   PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq));
2710a96aa3bSJed Brown   PetscFunctionReturn(0);
2720a96aa3bSJed Brown }
2730a96aa3bSJed Brown 
2740a96aa3bSJed Brown #define DMFTopologyCreate_pforest _append_pforest(DMFTopologyCreate)
2750a96aa3bSJed Brown static PetscErrorCode DMFTopologyCreate_pforest(DM dm, DMForestTopology topologyName, DMFTopology_pforest **topo)
2760a96aa3bSJed Brown {
2770a96aa3bSJed Brown   const char     *name = (const char*) topologyName;
2780a96aa3bSJed Brown   const char     *prefix;
2790a96aa3bSJed Brown   PetscBool      isBrick, isShell, isSphere, isMoebius;
2800a96aa3bSJed Brown 
2810a96aa3bSJed Brown   PetscFunctionBegin;
2820a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2830a96aa3bSJed Brown   PetscValidCharPointer(name,2);
2840a96aa3bSJed Brown   PetscValidPointer(topo,3);
2859566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"brick",&isBrick));
2869566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"shell",&isShell));
2879566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"sphere",&isSphere));
2889566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"moebius",&isMoebius));
2899566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
2900a96aa3bSJed Brown   if (isBrick) {
2910a96aa3bSJed Brown     PetscBool flgN, flgP, flgM, flgB, useMorton = PETSC_TRUE, periodic = PETSC_FALSE;
2920a96aa3bSJed Brown     PetscInt  N[3] = {2,2,2}, P[3] = {0,0,0}, nretN = P4EST_DIM, nretP = P4EST_DIM, nretB = 2 * P4EST_DIM, i;
2936858538eSMatthew G. Knepley     PetscReal B[6] = {0.0,1.0,0.0,1.0,0.0,1.0}, L[3] = {-1.0, -1.0, -1.0}, maxCell[3] = {-1.0, -1.0, -1.0};
2940a96aa3bSJed Brown 
2950a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
2969566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_size",N,&nretN,&flgN));
2979566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_periodicity",P,&nretP,&flgP));
2989566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_bounds",B,&nretB,&flgB));
2999566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_use_morton_curve",&useMorton,&flgM));
3001dca8a05SBarry Smith       PetscCheck(!flgN || nretN == P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d sizes in -dm_p4est_brick_size, gave %" PetscInt_FMT,P4EST_DIM,nretN);
3011dca8a05SBarry Smith       PetscCheck(!flgP || nretP == P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d periodicities in -dm_p4est_brick_periodicity, gave %" PetscInt_FMT,P4EST_DIM,nretP);
3021dca8a05SBarry Smith       PetscCheck(!flgB || nretB == 2 * P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d bounds in -dm_p4est_brick_bounds, gave %" PetscInt_FMT,P4EST_DIM,nretP);
3030a96aa3bSJed Brown     }
3040a96aa3bSJed Brown     for (i = 0; i < P4EST_DIM; i++) {
3050a96aa3bSJed Brown       P[i]  = (P[i] ? DM_BOUNDARY_PERIODIC : DM_BOUNDARY_NONE);
3060a96aa3bSJed Brown       periodic = (PetscBool)(P[i] || periodic);
3070a96aa3bSJed Brown       if (!flgB) B[2 * i + 1] = N[i];
3086858538eSMatthew G. Knepley       if (P[i]) {
3096858538eSMatthew G. Knepley         L[i] = B[2 * i + 1];
3106858538eSMatthew G. Knepley         maxCell[i] = 1.1 * (L[i] / N[i]);
3116858538eSMatthew G. Knepley       }
3120a96aa3bSJed Brown     }
3139566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,B,topo,useMorton));
3146858538eSMatthew G. Knepley     if (periodic) PetscCall(DMSetPeriodicity(dm, maxCell, L));
3150a96aa3bSJed Brown   } else {
3169566063dSJacob Faibussowitsch     PetscCall(PetscNewLog(dm,topo));
3170a96aa3bSJed Brown 
3180a96aa3bSJed Brown     (*topo)->refct = 1;
3190a96aa3bSJed Brown     PetscStackCallP4estReturn((*topo)->conn,p4est_connectivity_new_byname,(name));
3200a96aa3bSJed Brown     (*topo)->geom = NULL;
3211baa6e33SBarry Smith     if (isMoebius) PetscCall(DMSetCoordinateDim(dm,3));
3220a96aa3bSJed Brown #if defined(P4_TO_P8)
3230a96aa3bSJed Brown     if (isShell) {
3240a96aa3bSJed Brown       PetscReal R2 = 1., R1 = .55;
3250a96aa3bSJed Brown 
3260a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3279566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_outer_radius",&R2,NULL));
3289566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_inner_radius",&R1,NULL));
3290a96aa3bSJed Brown       }
3300a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_shell,((*topo)->conn,R2,R1));
3310a96aa3bSJed Brown     } else if (isSphere) {
3320a96aa3bSJed Brown       PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856;
3330a96aa3bSJed Brown 
3340a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3359566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_outer_radius",&R2,NULL));
3369566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_inner_radius",&R1,NULL));
3379566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_core_radius",&R0,NULL));
3380a96aa3bSJed Brown       }
3390a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_sphere,((*topo)->conn,R2,R1,R0));
3400a96aa3bSJed Brown     }
3410a96aa3bSJed Brown #endif
3429566063dSJacob Faibussowitsch     PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq));
3430a96aa3bSJed Brown   }
3440a96aa3bSJed Brown   PetscFunctionReturn(0);
3450a96aa3bSJed Brown }
3460a96aa3bSJed Brown 
3470a96aa3bSJed Brown #define DMConvert_plex_pforest _append_pforest(DMConvert_plex)
3480a96aa3bSJed Brown static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest)
3490a96aa3bSJed Brown {
3500a96aa3bSJed Brown   MPI_Comm       comm;
3510a96aa3bSJed Brown   PetscBool      isPlex;
3520a96aa3bSJed Brown   PetscInt       dim;
3530a96aa3bSJed Brown   void           *ctx;
3540a96aa3bSJed Brown 
3550a96aa3bSJed Brown   PetscFunctionBegin;
3560a96aa3bSJed Brown 
3570a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3580a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
3599566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex));
36028b400f6SJacob Faibussowitsch   PetscCheck(isPlex,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPLEX,((PetscObject)dm)->type_name);
3619566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dim));
36263a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim);
3639566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm,pforest));
3649566063dSJacob Faibussowitsch   PetscCall(DMSetType(*pforest,DMPFOREST));
3659566063dSJacob Faibussowitsch   PetscCall(DMForestSetBaseDM(*pforest,dm));
3669566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dm,&ctx));
3679566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(*pforest,ctx));
3689566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm,*pforest));
3690a96aa3bSJed Brown   PetscFunctionReturn(0);
3700a96aa3bSJed Brown }
3710a96aa3bSJed Brown 
3720a96aa3bSJed Brown #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
3730a96aa3bSJed Brown static PetscErrorCode DMForestDestroy_pforest(DM dm)
3740a96aa3bSJed Brown {
3750a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
3760a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
3770a96aa3bSJed Brown 
3780a96aa3bSJed Brown   PetscFunctionBegin;
3790a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3800a96aa3bSJed Brown   if (pforest->lnodes) PetscStackCallP4est(p4est_lnodes_destroy,(pforest->lnodes));
3810a96aa3bSJed Brown   pforest->lnodes = NULL;
3820a96aa3bSJed Brown   if (pforest->ghost) PetscStackCallP4est(p4est_ghost_destroy,(pforest->ghost));
3830a96aa3bSJed Brown   pforest->ghost = NULL;
3840a96aa3bSJed Brown   if (pforest->forest) PetscStackCallP4est(p4est_destroy,(pforest->forest));
3850a96aa3bSJed Brown   pforest->forest = NULL;
3869566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&pforest->topo));
3879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",NULL));
3889566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",NULL));
3892e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL));
3909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",NULL));
3912e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL));
3922e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL));
3939566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->ghostName));
3949566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&pforest->plex));
3959566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
3969566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
3979566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
3989566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
3999566063dSJacob Faibussowitsch   PetscCall(PetscFree(forest->data));
4000a96aa3bSJed Brown   PetscFunctionReturn(0);
4010a96aa3bSJed Brown }
4020a96aa3bSJed Brown 
4030a96aa3bSJed Brown #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
4040a96aa3bSJed Brown static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm)
4050a96aa3bSJed Brown {
4060a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4070a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest*) ((DM_Forest*) tdm->data)->data;
4080a96aa3bSJed Brown 
4090a96aa3bSJed Brown   PetscFunctionBegin;
4100a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
4119566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&(tpforest->topo)));
4120a96aa3bSJed Brown   tpforest->topo = pforest->topo;
4130a96aa3bSJed Brown   PetscFunctionReturn(0);
4140a96aa3bSJed Brown }
4150a96aa3bSJed Brown 
4160a96aa3bSJed Brown #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
4170a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM,p4est_connectivity_t**,PetscInt**);
4180a96aa3bSJed Brown 
4190a96aa3bSJed Brown typedef struct _PforestAdaptCtx
4200a96aa3bSJed Brown {
4210a96aa3bSJed Brown   PetscInt  maxLevel;
4220a96aa3bSJed Brown   PetscInt  minLevel;
4230a96aa3bSJed Brown   PetscInt  currLevel;
4240a96aa3bSJed Brown   PetscBool anyChange;
4250a96aa3bSJed Brown }
4260a96aa3bSJed Brown PforestAdaptCtx;
4270a96aa3bSJed Brown 
4280a96aa3bSJed Brown static int pforest_coarsen_currlevel(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4290a96aa3bSJed Brown {
4300a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx*) p4est->user_pointer;
4310a96aa3bSJed Brown   PetscInt        minLevel  = ctx->minLevel;
4320a96aa3bSJed Brown   PetscInt        currLevel = ctx->currLevel;
4330a96aa3bSJed Brown 
4340a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4350a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level == currLevel);
4360a96aa3bSJed Brown }
4370a96aa3bSJed Brown 
4380a96aa3bSJed Brown static int pforest_coarsen_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4390a96aa3bSJed Brown {
4400a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4410a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4420a96aa3bSJed Brown 
4430a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level > minLevel);
4440a96aa3bSJed Brown }
4450a96aa3bSJed Brown 
4460a96aa3bSJed Brown static int pforest_coarsen_flag_any(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4470a96aa3bSJed Brown {
4480a96aa3bSJed Brown   PetscInt        i;
4490a96aa3bSJed Brown   PetscBool       any      = PETSC_FALSE;
4500a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4510a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4520a96aa3bSJed Brown 
4530a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4540a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4550a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
4560a96aa3bSJed Brown       any = PETSC_FALSE;
4570a96aa3bSJed Brown       break;
4580a96aa3bSJed Brown     }
4590a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
4600a96aa3bSJed Brown       any = PETSC_TRUE;
4610a96aa3bSJed Brown       break;
4620a96aa3bSJed Brown     }
4630a96aa3bSJed Brown   }
4640a96aa3bSJed Brown   return any ? 1 : 0;
4650a96aa3bSJed Brown }
4660a96aa3bSJed Brown 
4670a96aa3bSJed Brown static int pforest_coarsen_flag_all(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4680a96aa3bSJed Brown {
4690a96aa3bSJed Brown   PetscInt        i;
4700a96aa3bSJed Brown   PetscBool       all      = PETSC_TRUE;
4710a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4720a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4730a96aa3bSJed Brown 
4740a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4750a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4760a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
4770a96aa3bSJed Brown       all = PETSC_FALSE;
4780a96aa3bSJed Brown       break;
4790a96aa3bSJed Brown     }
4800a96aa3bSJed Brown   }
4810a96aa3bSJed Brown   return all ? 1 : 0;
4820a96aa3bSJed Brown }
4830a96aa3bSJed Brown 
4840a96aa3bSJed Brown static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4850a96aa3bSJed Brown {
4860a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
4870a96aa3bSJed Brown }
4880a96aa3bSJed Brown 
4890a96aa3bSJed Brown static int pforest_refine_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4900a96aa3bSJed Brown {
4910a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4920a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
4930a96aa3bSJed Brown 
4940a96aa3bSJed Brown   return ((PetscInt) quadrant->level < maxLevel);
4950a96aa3bSJed Brown }
4960a96aa3bSJed Brown 
4970a96aa3bSJed Brown static int pforest_refine_flag(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4980a96aa3bSJed Brown {
4990a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
5000a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
5010a96aa3bSJed Brown 
5020a96aa3bSJed Brown   if ((PetscInt) quadrant->level >= maxLevel) return 0;
5030a96aa3bSJed Brown 
5040a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
5050a96aa3bSJed Brown }
5060a96aa3bSJed Brown 
5070a96aa3bSJed 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)
5080a96aa3bSJed Brown {
5090a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
5100a96aa3bSJed Brown   p4est_topidx_t t;
5110a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
5120a96aa3bSJed Brown 
5130a96aa3bSJed Brown   PetscFunctionBegin;
5140a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
5150a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t*) p4estFrom->trees->array)[t]);
5160a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t*) p4estTo->trees->array)[t]);
5170a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
5180a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
5190a96aa3bSJed Brown     PetscInt         numFrom    = (PetscInt) treeFrom->quadrants.elem_count;
5200a96aa3bSJed Brown     PetscInt         numTo      = (PetscInt) treeTo->quadrants.elem_count;
5210a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t*) treeFrom->quadrants.array;
5220a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t*) treeTo->quadrants.array;
5230a96aa3bSJed Brown     PetscInt         currentFrom, currentTo;
5240a96aa3bSJed Brown     PetscInt         treeOffsetFrom = (PetscInt) treeFrom->quadrants_offset;
5250a96aa3bSJed Brown     PetscInt         treeOffsetTo   = (PetscInt) treeTo->quadrants_offset;
5260a96aa3bSJed Brown     int              comp;
5270a96aa3bSJed Brown 
5280a96aa3bSJed Brown     PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(firstFrom,firstTo));
52928b400f6SJacob Faibussowitsch     PetscCheck(comp,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"non-matching partitions");
5300a96aa3bSJed Brown 
5310a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
5320a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
5330a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
5340a96aa3bSJed Brown 
5350a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
5360a96aa3bSJed Brown         if (toLeaves) {
5370a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5380a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
5390a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5400a96aa3bSJed Brown         }
5410a96aa3bSJed Brown         toFineLeaves++;
5420a96aa3bSJed Brown         currentFrom++;
5430a96aa3bSJed Brown         currentTo++;
5440a96aa3bSJed Brown       } else {
5450a96aa3bSJed Brown         int fromIsAncestor;
5460a96aa3bSJed Brown 
5470a96aa3bSJed Brown         PetscStackCallP4estReturn(fromIsAncestor,p4est_quadrant_is_ancestor,(quadFrom,quadTo));
5480a96aa3bSJed Brown         if (fromIsAncestor) {
5490a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5500a96aa3bSJed Brown 
5510a96aa3bSJed Brown           if (toLeaves) {
5520a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5530a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
5540a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5550a96aa3bSJed Brown           }
5560a96aa3bSJed Brown           toFineLeaves++;
5570a96aa3bSJed Brown           currentTo++;
5580a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadFrom,&lastDesc,quadTo->level));
5590a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadTo,&lastDesc));
5600a96aa3bSJed Brown           if (comp) currentFrom++;
5610a96aa3bSJed Brown         } else {
5620a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5630a96aa3bSJed Brown 
5640a96aa3bSJed Brown           if (fromLeaves) {
5650a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
5660a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
5670a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
5680a96aa3bSJed Brown           }
5690a96aa3bSJed Brown           fromFineLeaves++;
5700a96aa3bSJed Brown           currentFrom++;
5710a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadTo,&lastDesc,quadFrom->level));
5720a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadFrom,&lastDesc));
5730a96aa3bSJed Brown           if (comp) currentTo++;
5740a96aa3bSJed Brown         }
5750a96aa3bSJed Brown       }
5760a96aa3bSJed Brown     }
5770a96aa3bSJed Brown   }
5780a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
5790a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
5800a96aa3bSJed Brown   PetscFunctionReturn(0);
5810a96aa3bSJed Brown }
5820a96aa3bSJed Brown 
5830a96aa3bSJed Brown /* Compute the maximum level across all the trees */
5840a96aa3bSJed Brown static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev)
5850a96aa3bSJed Brown {
5860a96aa3bSJed Brown   p4est_topidx_t    t, flt, llt;
5870a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
5880a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
5890a96aa3bSJed Brown   PetscInt          maxlevelloc = 0;
5900a96aa3bSJed Brown   p4est_t           *p4est;
5910a96aa3bSJed Brown 
5920a96aa3bSJed Brown   PetscFunctionBegin;
59328b400f6SJacob Faibussowitsch   PetscCheck(pforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing DM_Forest_pforest");
59428b400f6SJacob Faibussowitsch   PetscCheck(pforest->forest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing p4est_t");
5950a96aa3bSJed Brown   p4est = pforest->forest;
5960a96aa3bSJed Brown   flt   = p4est->first_local_tree;
5970a96aa3bSJed Brown   llt   = p4est->last_local_tree;
5980a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
5990a96aa3bSJed Brown     p4est_tree_t *tree  = &(((p4est_tree_t*) p4est->trees->array)[t]);
6000a96aa3bSJed Brown     maxlevelloc = PetscMax((PetscInt)tree->maxlevel,maxlevelloc);
6010a96aa3bSJed Brown   }
6021c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&maxlevelloc,lev,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
6030a96aa3bSJed Brown   PetscFunctionReturn(0);
6040a96aa3bSJed Brown }
6050a96aa3bSJed Brown 
6060a96aa3bSJed Brown /* Puts identity in coarseToFine */
6070a96aa3bSJed Brown /* assumes a matching partition */
6080a96aa3bSJed Brown static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine)
6090a96aa3bSJed Brown {
6100a96aa3bSJed Brown   p4est_topidx_t flt, llt;
6110a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
6120a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
6130a96aa3bSJed Brown   PetscInt       *fromLeaves = NULL, *toLeaves = NULL;
6140a96aa3bSJed Brown   PetscSFNode    *fromRoots  = NULL, *toRoots = NULL;
6150a96aa3bSJed Brown 
6160a96aa3bSJed Brown   PetscFunctionBegin;
6170a96aa3bSJed Brown   flt  = p4estFrom->first_local_tree;
6180a96aa3bSJed Brown   llt  = p4estFrom->last_local_tree;
6199566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm,&fromCoarse));
6200a96aa3bSJed Brown   if (toCoarseFromFine) {
6219566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm,&toCoarse));
6220a96aa3bSJed Brown   }
6230a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
6240a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
6259566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,NULL,NULL,&numLeavesFrom,NULL,NULL));
6269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo,&toLeaves));
6279566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo,&fromRoots));
6280a96aa3bSJed Brown   if (toCoarseFromFine) {
6299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom,&fromLeaves));
6309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom,&fromRoots));
6310a96aa3bSJed Brown   }
6329566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,toLeaves,fromRoots,&numLeavesFrom,fromLeaves,toRoots));
6330a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
6349566063dSJacob Faibussowitsch     PetscCall(PetscFree(toLeaves));
6359566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,NULL,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER));
6361baa6e33SBarry Smith   } else PetscCall(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,toLeaves,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER));
6370a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
6380a96aa3bSJed Brown   if (toCoarseFromFine) {
6399566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(toCoarse,numRootsTo,numLeavesFrom,fromLeaves,PETSC_OWN_POINTER,toRoots,PETSC_OWN_POINTER));
6400a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
6410a96aa3bSJed Brown   }
6420a96aa3bSJed Brown   PetscFunctionReturn(0);
6430a96aa3bSJed Brown }
6440a96aa3bSJed Brown 
6450a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
6460a96aa3bSJed Brown static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB)
6470a96aa3bSJed Brown {
6480a96aa3bSJed Brown   p4est_quadrant_t * myCoarseStart = &(p4estA->global_first_position[rank]);
6490a96aa3bSJed Brown   p4est_quadrant_t * myCoarseEnd   = &(p4estA->global_first_position[rank+1]);
6500a96aa3bSJed Brown   p4est_quadrant_t * globalFirstB  = p4estB->global_first_position;
6510a96aa3bSJed Brown 
6520a96aa3bSJed Brown   PetscFunctionBegin;
6530a96aa3bSJed Brown   *startB = -1;
6540a96aa3bSJed Brown   *endB   = -1;
6550a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
6560a96aa3bSJed Brown     PetscInt lo, hi, guess;
6570a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
6580a96aa3bSJed Brown     lo    = 0;
6590a96aa3bSJed Brown     hi    = size;
6600a96aa3bSJed Brown     guess = rank;
6610a96aa3bSJed Brown     while (1) {
6620a96aa3bSJed Brown       int startCompMy, myCompEnd;
6630a96aa3bSJed Brown 
6640a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseStart));
6650a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseStart,&globalFirstB[guess+1]));
6660a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
6670a96aa3bSJed Brown         *startB = guess;
6680a96aa3bSJed Brown         break;
6690a96aa3bSJed Brown       } else if (startCompMy > 0) {  /* guess is to high */
6700a96aa3bSJed Brown         hi = guess;
6710a96aa3bSJed Brown       } else { /* guess is to low */
6720a96aa3bSJed Brown         lo = guess + 1;
6730a96aa3bSJed Brown       }
6740a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6750a96aa3bSJed Brown     }
6760a96aa3bSJed Brown     /* reset bounds, but not guess */
6770a96aa3bSJed Brown     lo = 0;
6780a96aa3bSJed Brown     hi = size;
6790a96aa3bSJed Brown     while (1) {
6800a96aa3bSJed Brown       int startCompMy, myCompEnd;
6810a96aa3bSJed Brown 
6820a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseEnd));
6830a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseEnd,&globalFirstB[guess+1]));
6840a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
6850a96aa3bSJed Brown         *endB = guess + 1;
6860a96aa3bSJed Brown         break;
6870a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
6880a96aa3bSJed Brown         hi = guess;
6890a96aa3bSJed Brown       } else { /* guess is to low */
6900a96aa3bSJed Brown         lo = guess + 1;
6910a96aa3bSJed Brown       }
6920a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6930a96aa3bSJed Brown     }
6940a96aa3bSJed Brown   }
6950a96aa3bSJed Brown   PetscFunctionReturn(0);
6960a96aa3bSJed Brown }
6970a96aa3bSJed Brown 
6980a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM,DM*);
6990a96aa3bSJed Brown 
7000a96aa3bSJed Brown #define DMSetUp_pforest _append_pforest(DMSetUp)
7010a96aa3bSJed Brown static PetscErrorCode DMSetUp_pforest(DM dm)
7020a96aa3bSJed Brown {
7030a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
7040a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
7050a96aa3bSJed Brown   DM                base, adaptFrom;
7060a96aa3bSJed Brown   DMForestTopology  topoName;
7070a96aa3bSJed Brown   PetscSF           preCoarseToFine = NULL, coarseToPreFine = NULL;
7080a96aa3bSJed Brown   PforestAdaptCtx   ctx;
7090a96aa3bSJed Brown 
7100a96aa3bSJed Brown   PetscFunctionBegin;
7110a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
7120a96aa3bSJed Brown   ctx.maxLevel  = 0;
7130a96aa3bSJed Brown   ctx.currLevel = 0;
7140a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
7150a96aa3bSJed Brown   /* sanity check */
7169566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm,&adaptFrom));
7179566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
7189566063dSJacob Faibussowitsch   PetscCall(DMForestGetTopology(dm,&topoName));
7191dca8a05SBarry Smith   PetscCheck(adaptFrom || base || topoName,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"A forest needs a topology, a base DM, or a DM to adapt from");
7200a96aa3bSJed Brown 
7210a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
7220a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
7230a96aa3bSJed Brown     PetscBool         ispforest;
7240a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
7250a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
7260a96aa3bSJed Brown 
7279566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)adaptFrom,DMPFOREST,&ispforest));
72828b400f6SJacob Faibussowitsch     PetscCheck(ispforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Trying to adapt from %s, which is not %s",((PetscObject)adaptFrom)->type_name,DMPFOREST);
72928b400f6SJacob Faibussowitsch     PetscCheck(apforest->topo,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"The pre-adaptation forest must have a topology");
7309566063dSJacob Faibussowitsch     PetscCall(DMSetUp(adaptFrom));
7319566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm,&base));
7329566063dSJacob Faibussowitsch     PetscCall(DMForestGetTopology(dm,&topoName));
7330a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
7340a96aa3bSJed Brown     PetscBool isPlex, isDA;
7350a96aa3bSJed Brown 
7369566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)base,&topoName));
7379566063dSJacob Faibussowitsch     PetscCall(DMForestSetTopology(dm,topoName));
7389566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base,DMPLEX,&isPlex));
7399566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base,DMDA,&isDA));
7400a96aa3bSJed Brown     if (isPlex) {
7410a96aa3bSJed Brown       MPI_Comm             comm = PetscObjectComm((PetscObject)dm);
7420a96aa3bSJed Brown       PetscInt             depth;
7430a96aa3bSJed Brown       PetscMPIInt          size;
7440a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
7450a96aa3bSJed Brown       DMFTopology_pforest  *topo;
7460a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
7470a96aa3bSJed Brown 
7489566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepth(base,&depth));
7490a96aa3bSJed Brown       if (depth == 1) {
7500a96aa3bSJed Brown         DM connDM;
7510a96aa3bSJed Brown 
7529566063dSJacob Faibussowitsch         PetscCall(DMPlexInterpolate(base,&connDM));
7530a96aa3bSJed Brown         base = connDM;
7549566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm,base));
7559566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&connDM));
75663a3b9bcSJacob Faibussowitsch       } else PetscCheck(depth == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Base plex is neither interpolated nor uninterpolated? depth %" PetscInt_FMT ", expected 2 or %d",depth,P4EST_DIM + 1);
7579566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(comm,&size));
7580a96aa3bSJed Brown       if (size > 1) {
7590a96aa3bSJed Brown         DM      dmRedundant;
7600a96aa3bSJed Brown         PetscSF sf;
7610a96aa3bSJed Brown 
7629566063dSJacob Faibussowitsch         PetscCall(DMPlexGetRedundantDM(base,&sf,&dmRedundant));
76328b400f6SJacob Faibussowitsch         PetscCheck(dmRedundant,comm,PETSC_ERR_PLIB,"Could not create redundant DM");
7649566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)dmRedundant,"_base_migration_sf",(PetscObject)sf));
7659566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&sf));
7660a96aa3bSJed Brown         base = dmRedundant;
7679566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm,base));
7689566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&dmRedundant));
7690a96aa3bSJed Brown       }
7709566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(base,NULL,"-dm_p4est_base_view"));
7719566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateConnectivity_pforest(base,&conn,&tree_face_to_uniq));
7729566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(dm,&topo));
7730a96aa3bSJed Brown       topo->refct = 1;
7740a96aa3bSJed Brown       topo->conn  = conn;
7750a96aa3bSJed Brown       topo->geom  = NULL;
7760a96aa3bSJed Brown       {
7770a96aa3bSJed Brown         PetscErrorCode (*map)(DM,PetscInt,PetscInt,const PetscReal[],PetscReal[],void*);
7780a96aa3bSJed Brown         void           *mapCtx;
7790a96aa3bSJed Brown 
7809566063dSJacob Faibussowitsch         PetscCall(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx));
7810a96aa3bSJed Brown         if (map) {
7820a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
7830a96aa3bSJed Brown           p4est_geometry_t           *geom;
7840a96aa3bSJed Brown 
7859566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom_pforest));
7869566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinateDim(dm,&geom_pforest->coordDim));
7870a96aa3bSJed Brown           geom_pforest->map    = map;
7880a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
7890a96aa3bSJed Brown           PetscStackCallP4estReturn(geom_pforest->inner,p4est_geometry_new_connectivity,(conn));
7909566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom));
7910a96aa3bSJed Brown           geom->name    = topoName;
7920a96aa3bSJed Brown           geom->user    = geom_pforest;
7930a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
7940a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
7950a96aa3bSJed Brown           topo->geom    = geom;
7960a96aa3bSJed Brown         }
7970a96aa3bSJed Brown       }
7980a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
7990a96aa3bSJed Brown       pforest->topo           = topo;
80028b400f6SJacob Faibussowitsch     } else PetscCheck(!isDA,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Not implemented yet");
8010a96aa3bSJed Brown #if 0
8020a96aa3bSJed Brown       PetscInt N[3], P[3];
8030a96aa3bSJed Brown 
8040a96aa3bSJed Brown       /* get the sizes, periodicities */
8050a96aa3bSJed Brown       /* ... */
8060a96aa3bSJed Brown                                                                   /* don't use Morton order */
8079566063dSJacob Faibussowitsch       PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE));
8080a96aa3bSJed Brown #endif
8090a96aa3bSJed Brown     {
8100a96aa3bSJed Brown       PetscInt numLabels, l;
8110a96aa3bSJed Brown 
8129566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(base,&numLabels));
8130a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
8140a96aa3bSJed Brown         PetscBool  isDepth, isGhost, isVTK, isDim, isCellType;
8150a96aa3bSJed Brown         DMLabel    label, labelNew;
8160a96aa3bSJed Brown         PetscInt   defVal;
8170a96aa3bSJed Brown         const char *name;
8180a96aa3bSJed Brown 
8199566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(base, l, &name));
8209566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(base, l, &label));
8219566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"depth",&isDepth));
8220a96aa3bSJed Brown         if (isDepth) continue;
8239566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"dim",&isDim));
8240a96aa3bSJed Brown         if (isDim) continue;
8259566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"celltype",&isCellType));
8260a96aa3bSJed Brown         if (isCellType) continue;
8279566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"ghost",&isGhost));
8280a96aa3bSJed Brown         if (isGhost) continue;
8299566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"vtk",&isVTK));
8300a96aa3bSJed Brown         if (isVTK) continue;
8319566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,name));
8329566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm,name,&labelNew));
8339566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label,&defVal));
8349566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew,defVal));
8350a96aa3bSJed Brown       }
8360a96aa3bSJed Brown       /* map dm points (internal plex) to base
8370a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
8380a96aa3bSJed Brown          and propagating back to the coarsest
8390a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
8400a96aa3bSJed Brown          during DMForestTransferVecFromBase */
8419566063dSJacob Faibussowitsch       PetscCall(DMForestGetMinimumRefinement(dm,&l));
8420a96aa3bSJed Brown       if (!l) {
8439566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,"_forest_base_subpoint_map"));
8440a96aa3bSJed Brown       }
8450a96aa3bSJed Brown     }
8460a96aa3bSJed Brown   } else { /* construct from topology name */
8470a96aa3bSJed Brown     DMFTopology_pforest *topo;
8480a96aa3bSJed Brown 
8499566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreate_pforest(dm,topoName,&topo));
8500a96aa3bSJed Brown     pforest->topo = topo;
8510a96aa3bSJed Brown     /* TODO: construct base? */
8520a96aa3bSJed Brown   }
8530a96aa3bSJed Brown 
8540a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
8550a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
8560a96aa3bSJed Brown     DMLabel           adaptLabel;
8570a96aa3bSJed Brown     PetscInt          defaultValue;
8580a96aa3bSJed Brown     PetscInt          numValues, numValuesGlobal, cLocalStart, count;
8590a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
8600a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
8610a96aa3bSJed Brown     PetscBool         computeAdaptSF;
8620a96aa3bSJed Brown     p4est_topidx_t    flt, llt, t;
8630a96aa3bSJed Brown 
8640a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
8650a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
8660a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
8679566063dSJacob Faibussowitsch     PetscCall(DMForestGetComputeAdaptivitySF(dm,&computeAdaptSF));
8680a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_copy,(apforest->forest, 0)); /* 0 indicates no data copying */
8699566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm,&adaptLabel));
8700a96aa3bSJed Brown     if (adaptLabel) {
8710a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
8729566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(adaptLabel,&numValues));
8739566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&numValues,&numValuesGlobal,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)adaptFrom)));
8749566063dSJacob Faibussowitsch       PetscCall(DMLabelGetDefaultValue(adaptLabel,&defaultValue));
8750a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
8769566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
8779566063dSJacob Faibussowitsch         PetscCall(DMPforestGetRefinementLevel(dm,&ctx.currLevel));
8780a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8790a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_currlevel,NULL));
8800a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8810a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8820a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
8830a96aa3bSJed Brown         if (computeAdaptSF) {
8849566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL));
8850a96aa3bSJed Brown         }
8860a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */
8879566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
8880a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8890a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_uniform,NULL));
8900a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8910a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8920a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
8930a96aa3bSJed Brown         if (computeAdaptSF) {
8949566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL));
8950a96aa3bSJed Brown         }
8960a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
8979566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&ctx.maxLevel));
8980a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8990a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_uniform,NULL));
9000a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
9010a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
9020a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
9030a96aa3bSJed Brown         if (computeAdaptSF) {
9049566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,NULL));
9050a96aa3bSJed Brown         }
9060a96aa3bSJed Brown       } else if (numValuesGlobal) {
9070a96aa3bSJed Brown         p4est_t                    *p4est = pforest->forest;
9080a96aa3bSJed Brown         PetscInt                   *cellFlags;
9090a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
9100a96aa3bSJed Brown         PetscSF                    cellSF;
9110a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
9120a96aa3bSJed Brown         PetscBool                  adaptAny;
9130a96aa3bSJed Brown 
9149566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&ctx.maxLevel));
9159566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
9169566063dSJacob Faibussowitsch         PetscCall(DMForestGetAdaptivityStrategy(dm,&strategy));
9179566063dSJacob Faibussowitsch         PetscCall(PetscStrncmp(strategy,"any",3,&adaptAny));
9189566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellChart(adaptFrom,&cStart,&cEnd));
9199566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellSF(adaptFrom,&cellSF));
9209566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cEnd-cStart,&cellFlags));
9219566063dSJacob Faibussowitsch         for (c = cStart; c < cEnd; c++) PetscCall(DMLabelGetValue(adaptLabel,c,&cellFlags[c-cStart]));
9220a96aa3bSJed Brown         if (cellSF) {
9230a96aa3bSJed Brown           if (adaptAny) {
9249566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX));
9259566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX));
9260a96aa3bSJed Brown           } else {
9279566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN));
9289566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN));
9290a96aa3bSJed Brown           }
9300a96aa3bSJed Brown         }
9310a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
9320a96aa3bSJed Brown           p4est_tree_t       *tree    = &(((p4est_tree_t*) p4est->trees->array)[t]);
9330a96aa3bSJed Brown           PetscInt           numQuads = (PetscInt) tree->quadrants.elem_count, i;
9340a96aa3bSJed Brown           p4est_quadrant_t   *quads   = (p4est_quadrant_t *) tree->quadrants.array;
9350a96aa3bSJed Brown 
9360a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9370a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
9380a96aa3bSJed Brown             q->p.user_int = cellFlags[count++];
9390a96aa3bSJed Brown           }
9400a96aa3bSJed Brown         }
9419566063dSJacob Faibussowitsch         PetscCall(PetscFree(cellFlags));
9420a96aa3bSJed Brown 
9430a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
9441baa6e33SBarry Smith         if (adaptAny) PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_any,pforest_init_determine));
9451baa6e33SBarry Smith         else PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_all,pforest_init_determine));
9460a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_flag,NULL));
9470a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
9480a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
9490a96aa3bSJed Brown         if (computeAdaptSF) {
9509566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,&coarseToPreFine));
9510a96aa3bSJed Brown         }
9520a96aa3bSJed Brown       }
9530a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
9540a96aa3bSJed Brown         p4est_tree_t       *atree    = &(((p4est_tree_t*) apforest->forest->trees->array)[t]);
9550a96aa3bSJed Brown         p4est_tree_t       *tree     = &(((p4est_tree_t*) pforest->forest->trees->array)[t]);
9560a96aa3bSJed Brown         PetscInt           anumQuads = (PetscInt) atree->quadrants.elem_count, i;
9570a96aa3bSJed Brown         PetscInt           numQuads  = (PetscInt) tree->quadrants.elem_count;
9580a96aa3bSJed Brown         p4est_quadrant_t   *aquads   = (p4est_quadrant_t *) atree->quadrants.array;
9590a96aa3bSJed Brown         p4est_quadrant_t   *quads    = (p4est_quadrant_t *) tree->quadrants.array;
9600a96aa3bSJed Brown 
9610a96aa3bSJed Brown         if (anumQuads != numQuads) {
9620a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
9630a96aa3bSJed Brown         } else {
9640a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9650a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
9660a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
9670a96aa3bSJed Brown 
9680a96aa3bSJed Brown             if (aq->level != q->level) {
9690a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
9700a96aa3bSJed Brown               break;
9710a96aa3bSJed Brown             }
9720a96aa3bSJed Brown           }
9730a96aa3bSJed Brown         }
9740a96aa3bSJed Brown         if (ctx.anyChange) {
9750a96aa3bSJed Brown           break;
9760a96aa3bSJed Brown         }
9770a96aa3bSJed Brown       }
9780a96aa3bSJed Brown     }
9790a96aa3bSJed Brown     {
9800a96aa3bSJed Brown       PetscInt numLabels, l;
9810a96aa3bSJed Brown 
9829566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(adaptFrom,&numLabels));
9830a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
9840a96aa3bSJed Brown         PetscBool  isDepth, isCellType, isGhost, isVTK;
9850a96aa3bSJed Brown         DMLabel    label, labelNew;
9860a96aa3bSJed Brown         PetscInt   defVal;
9870a96aa3bSJed Brown         const char *name;
9880a96aa3bSJed Brown 
9899566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(adaptFrom, l, &name));
9909566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(adaptFrom, l, &label));
9919566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"depth",&isDepth));
9920a96aa3bSJed Brown         if (isDepth) continue;
9939566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"celltype",&isCellType));
9940a96aa3bSJed Brown         if (isCellType) continue;
9959566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"ghost",&isGhost));
9960a96aa3bSJed Brown         if (isGhost) continue;
9979566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"vtk",&isVTK));
9980a96aa3bSJed Brown         if (isVTK) continue;
9999566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,name));
10009566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm,name,&labelNew));
10019566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label,&defVal));
10029566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew,defVal));
10030a96aa3bSJed Brown       }
10040a96aa3bSJed Brown     }
10050a96aa3bSJed Brown   } else { /* initial */
10060a96aa3bSJed Brown     PetscInt initLevel, minLevel;
1007*66c0a4b5SToby Isaac #if defined(PETSC_HAVE_MPIUNI)
1008*66c0a4b5SToby Isaac     sc_MPI_Comm comm = sc_MPI_COMM_WORLD;
1009*66c0a4b5SToby Isaac #else
1010*66c0a4b5SToby Isaac     MPI_Comm comm = PetscObjectComm((PetscObject)dm);
1011*66c0a4b5SToby Isaac #endif
10120a96aa3bSJed Brown 
10139566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm,&initLevel));
10149566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
1015*66c0a4b5SToby Isaac     PetscStackCallP4estReturn(pforest->forest,p4est_new_ext,(comm,pforest->topo->conn,
10160a96aa3bSJed Brown                                                              0,           /* minimum number of quadrants per processor */
10170a96aa3bSJed Brown                                                              initLevel,   /* level of refinement */
10180a96aa3bSJed Brown                                                              1,           /* uniform refinement */
10190a96aa3bSJed Brown                                                              0,           /* we don't allocate any per quadrant data */
10200a96aa3bSJed Brown                                                              NULL,        /* there is no special quadrant initialization */
10210a96aa3bSJed Brown                                                              (void*)dm)); /* this dm is the user context */
10220a96aa3bSJed Brown 
10230a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10240a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
10250a96aa3bSJed Brown       PetscBool  flgPattern, flgFractal;
10260a96aa3bSJed Brown       PetscInt   corner = 0;
10270a96aa3bSJed Brown       PetscInt   corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
10280a96aa3bSJed Brown       PetscReal  likelihood = 1./ P4EST_DIM;
10290a96aa3bSJed Brown       PetscInt   pattern;
10300a96aa3bSJed Brown       const char *prefix;
10310a96aa3bSJed Brown 
10329566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
10339566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEList(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_pattern",DMRefinePatternName,PATTERN_COUNT,&pattern,&flgPattern));
10349566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_corner",&corner,NULL));
10359566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_fractal_corners",corners,&ncorner,&flgFractal));
10369566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_hash_likelihood",&likelihood,NULL));
10370a96aa3bSJed Brown 
10380a96aa3bSJed Brown       if (flgPattern) {
10390a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
10400a96aa3bSJed Brown         PetscInt           maxLevel;
10410a96aa3bSJed Brown 
10429566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&maxLevel));
10439566063dSJacob Faibussowitsch         PetscCall(PetscNewLog(dm,&ctx));
10440a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel,P4EST_QMAXLEVEL);
10450a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10460a96aa3bSJed Brown         switch (pattern) {
10470a96aa3bSJed Brown         case PATTERN_HASH:
10480a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
10490a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
10500a96aa3bSJed Brown           break;
10510a96aa3bSJed Brown         case PATTERN_CORNER:
10520a96aa3bSJed Brown           ctx->corner    = corner;
10530a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
10540a96aa3bSJed Brown           break;
10550a96aa3bSJed Brown         case PATTERN_CENTER:
10560a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Center;
10570a96aa3bSJed Brown           break;
10580a96aa3bSJed Brown         case PATTERN_FRACTAL:
10590a96aa3bSJed Brown           if (flgFractal) {
10600a96aa3bSJed Brown             PetscInt i;
10610a96aa3bSJed Brown 
10620a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
10630a96aa3bSJed Brown           } else {
10640a96aa3bSJed Brown #if !defined(P4_TO_P8)
10650a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
10660a96aa3bSJed Brown #else
10670a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
10680a96aa3bSJed Brown #endif
10690a96aa3bSJed Brown           }
10700a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
10710a96aa3bSJed Brown           break;
10720a96aa3bSJed Brown         default:
10730a96aa3bSJed Brown           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Not a valid refinement pattern");
10740a96aa3bSJed Brown         }
10750a96aa3bSJed Brown 
10760a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) ctx;
10770a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,1,ctx->refine_fn,NULL));
10780a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
10799566063dSJacob Faibussowitsch         PetscCall(PetscFree(ctx));
10800a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
10810a96aa3bSJed Brown       }
10820a96aa3bSJed Brown     }
10830a96aa3bSJed Brown   }
10840a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
10850a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
10860a96aa3bSJed Brown 
10879566063dSJacob Faibussowitsch     PetscCall(DMPforestGetRefinementLevel(dm,&currLevel));
10889566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm,&initLevel));
10899566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
10900a96aa3bSJed Brown     if (currLevel > minLevel) {
10910a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
10920a96aa3bSJed Brown       DMLabel           coarsen;
10930a96aa3bSJed Brown       DM                coarseDM;
10940a96aa3bSJed Brown 
10959566063dSJacob Faibussowitsch       PetscCall(DMForestTemplate(dm,MPI_COMM_NULL,&coarseDM));
10969566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityPurpose(coarseDM,DM_ADAPT_COARSEN));
10979566063dSJacob Faibussowitsch       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen",&coarsen));
10989566063dSJacob Faibussowitsch       PetscCall(DMLabelSetDefaultValue(coarsen,DM_ADAPT_COARSEN));
10999566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityLabel(coarseDM,coarsen));
11009566063dSJacob Faibussowitsch       PetscCall(DMLabelDestroy(&coarsen));
11019566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm,coarseDM));
11029566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)coarseDM));
11030a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
11049566063dSJacob Faibussowitsch       PetscCall(DMForestSetInitialRefinement(coarseDM,initLevel));
11059566063dSJacob Faibussowitsch       PetscCall(DMForestSetMinimumRefinement(coarseDM,minLevel));
11060a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest*) ((DM_Forest*) coarseDM->data)->data;
11070a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
11080a96aa3bSJed Brown     }
11090a96aa3bSJed Brown   }
11100a96aa3bSJed Brown 
11110a96aa3bSJed Brown   { /* repartitioning and overlap */
11120a96aa3bSJed Brown     PetscMPIInt size, rank;
11130a96aa3bSJed Brown 
11149566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size));
11159566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
11160a96aa3bSJed Brown     if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
11170a96aa3bSJed Brown       PetscBool      copyForest   = PETSC_FALSE;
11180a96aa3bSJed Brown       p4est_t        *forest_copy = NULL;
11190a96aa3bSJed Brown       p4est_gloidx_t shipped      = 0;
11200a96aa3bSJed Brown 
11210a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
11220a96aa3bSJed Brown       if (copyForest) PetscStackCallP4estReturn(forest_copy,p4est_copy,(pforest->forest,0));
11230a96aa3bSJed Brown 
11240a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
11250a96aa3bSJed Brown         PetscStackCallP4estReturn(shipped,p4est_partition_ext,(pforest->forest,(int)pforest->partition_for_coarsening,NULL));
11260a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Non-uniform partition cases not implemented yet");
11270a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
11280a96aa3bSJed Brown       if (forest_copy) {
11290a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
11300a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
11310a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
11320a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
11330a96aa3bSJed Brown           PetscSFNode    *repartRoots;
11340a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
11350a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank+1];
11360a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
11370a96aa3bSJed Brown 
11380a96aa3bSJed Brown           numRoots  = (PetscInt) (forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
11390a96aa3bSJed Brown           numLeaves = (PetscInt) (postEnd - postStart);
11409566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeOverlappingRanks(size,rank,pforest->forest,forest_copy,&pStart,&pEnd));
11419566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1((PetscInt) pforest->forest->local_num_quadrants,&repartRoots));
11420a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
11430a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
11440a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p+1];
11450a96aa3bSJed Brown             PetscInt       q;
11460a96aa3bSJed Brown 
11470a96aa3bSJed Brown             if (preEnd == preStart) continue;
114808401ef6SPierre Jolivet             PetscCheck(preStart <= postStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Bad partition overlap computation");
11490a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
11500a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
11510a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
11520a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
11530a96aa3bSJed Brown             }
11540a96aa3bSJed Brown             partOffset = preEnd;
11550a96aa3bSJed Brown           }
11569566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&repartSF));
11579566063dSJacob Faibussowitsch           PetscCall(PetscSFSetGraph(repartSF,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,repartRoots,PETSC_OWN_POINTER));
11589566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(repartSF));
11590a96aa3bSJed Brown           if (preCoarseToFine) {
11600a96aa3bSJed Brown             PetscSF        repartSFembed, preCoarseToFineNew;
11610a96aa3bSJed Brown             PetscInt       nleaves;
11620a96aa3bSJed Brown             const PetscInt *leaves;
11630a96aa3bSJed Brown 
11649566063dSJacob Faibussowitsch             PetscCall(PetscSFSetUp(preCoarseToFine));
11659566063dSJacob Faibussowitsch             PetscCall(PetscSFGetGraph(preCoarseToFine,NULL,&nleaves,&leaves,NULL));
11660a96aa3bSJed Brown             if (leaves) {
11679566063dSJacob Faibussowitsch               PetscCall(PetscSFCreateEmbeddedRootSF(repartSF,nleaves,leaves,&repartSFembed));
11680a96aa3bSJed Brown             } else {
11690a96aa3bSJed Brown               repartSFembed = repartSF;
11709566063dSJacob Faibussowitsch               PetscCall(PetscObjectReference((PetscObject)repartSFembed));
11710a96aa3bSJed Brown             }
11729566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(preCoarseToFine,repartSFembed,&preCoarseToFineNew));
11739566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&preCoarseToFine));
11749566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFembed));
11750a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
11760a96aa3bSJed Brown           }
11770a96aa3bSJed Brown           if (coarseToPreFine) {
11780a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
11790a96aa3bSJed Brown 
11809566063dSJacob Faibussowitsch             PetscCall(PetscSFCreateInverseSF(repartSF,&repartSFinv));
11819566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(repartSFinv,coarseToPreFine,&coarseToPreFineNew));
11829566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&coarseToPreFine));
11839566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFinv));
11840a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
11850a96aa3bSJed Brown           }
11869566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&repartSF));
11870a96aa3bSJed Brown         }
11880a96aa3bSJed Brown         PetscStackCallP4est(p4est_destroy,(forest_copy));
11890a96aa3bSJed Brown       }
11900a96aa3bSJed Brown     }
11910a96aa3bSJed Brown     if (size > 1) {
11920a96aa3bSJed Brown       PetscInt overlap;
11930a96aa3bSJed Brown 
11949566063dSJacob Faibussowitsch       PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
11950a96aa3bSJed Brown 
11960a96aa3bSJed Brown       if (adaptFrom) {
11970a96aa3bSJed Brown         PetscInt aoverlap;
11980a96aa3bSJed Brown 
11999566063dSJacob Faibussowitsch         PetscCall(DMForestGetPartitionOverlap(adaptFrom,&aoverlap));
12000a96aa3bSJed Brown         if (aoverlap != overlap) {
12010a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
12020a96aa3bSJed Brown         }
12030a96aa3bSJed Brown       }
12040a96aa3bSJed Brown 
12050a96aa3bSJed Brown       if (overlap > 0) {
12060a96aa3bSJed Brown         PetscInt i, cLocalStart;
12070a96aa3bSJed Brown         PetscInt cEnd;
12080a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
12090a96aa3bSJed Brown 
12100a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->ghost,p4est_ghost_new,(pforest->forest,P4EST_CONNECT_FULL));
12110a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->lnodes,p4est_lnodes_new,(pforest->forest,pforest->ghost,-P4EST_DIM));
12120a96aa3bSJed Brown         PetscStackCallP4est(p4est_ghost_support_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
12130a96aa3bSJed Brown         for (i = 1; i < overlap; i++) PetscStackCallP4est(p4est_ghost_expand_by_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
12140a96aa3bSJed Brown 
12150a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
12160a96aa3bSJed Brown         cEnd        = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
12170a96aa3bSJed Brown 
12180a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
12190a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
12209566063dSJacob Faibussowitsch           if (adaptFrom) PetscCall(DMForestGetCellSF(adaptFrom,&preCellSF));
12210a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
12229566063dSJacob Faibussowitsch           PetscCall(DMForestGetCellSF(dm,&cellSF));
12230a96aa3bSJed Brown         }
12240a96aa3bSJed Brown         if (preCoarseToFine) {
12250a96aa3bSJed Brown           PetscSF           preCoarseToFineNew;
12260a96aa3bSJed Brown           PetscInt          nleaves, nroots, *leavesNew, i, nleavesNew;
12270a96aa3bSJed Brown           const PetscInt    *leaves;
12280a96aa3bSJed Brown           const PetscSFNode *remotes;
12290a96aa3bSJed Brown           PetscSFNode       *remotesAll;
12300a96aa3bSJed Brown 
12319566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(preCoarseToFine));
12329566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCoarseToFine,&nroots,&nleaves,&leaves,&remotes));
12339566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(cEnd,&remotesAll));
12340a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
12350a96aa3bSJed Brown             remotesAll[i].rank  = -1;
12360a96aa3bSJed Brown             remotesAll[i].index = -1;
12370a96aa3bSJed Brown           }
12380a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
12399566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(cellSF));
12409566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE));
12419566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE));
12420a96aa3bSJed Brown           nleavesNew = 0;
12430a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12440a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
12450a96aa3bSJed Brown           }
12469566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesNew,&leavesNew));
12470a96aa3bSJed Brown           nleavesNew = 0;
12480a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12490a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
12500a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
12510a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
12520a96aa3bSJed Brown               nleavesNew++;
12530a96aa3bSJed Brown             }
12540a96aa3bSJed Brown           }
12559566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&preCoarseToFineNew));
12560a96aa3bSJed Brown           if (nleavesNew < cEnd) {
12579566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,leavesNew,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES));
12580a96aa3bSJed Brown           } else { /* all cells are leaves */
12599566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
12609566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,NULL,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES));
12610a96aa3bSJed Brown           }
12629566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesAll));
12639566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&preCoarseToFine));
12640a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12650a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12660a96aa3bSJed Brown         }
12670a96aa3bSJed Brown         if (coarseToPreFine) {
12680a96aa3bSJed Brown           PetscSF           coarseToPreFineNew;
12690a96aa3bSJed Brown           PetscInt          nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
12700a96aa3bSJed Brown           const PetscInt    *leaves;
12710a96aa3bSJed Brown           const PetscSFNode *remotes;
12720a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
12730a96aa3bSJed Brown 
12749566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(coarseToPreFine));
12759566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseToPreFine,&nroots,&nleaves,&leaves,&remotes));
12769566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCellSF,NULL,&nleavesCellSF,NULL,NULL));
12779566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nroots,&remotesNewRoot));
12789566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleaves,&remotesNew));
12790a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
12800a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
12810a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
12820a96aa3bSJed Brown           }
12839566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE));
12849566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE));
12859566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNewRoot));
12869566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesCellSF,&remotesExpanded));
12870a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12880a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
12890a96aa3bSJed Brown             remotesExpanded[i].index = -1;
12900a96aa3bSJed Brown           }
12910a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
12929566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNew));
12939566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE));
12949566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE));
12950a96aa3bSJed Brown 
12960a96aa3bSJed Brown           nleavesExpanded = 0;
12970a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12980a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
12990a96aa3bSJed Brown           }
13009566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesExpanded,&leavesNew));
13010a96aa3bSJed Brown           nleavesExpanded = 0;
13020a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
13030a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
13040a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
13050a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
13060a96aa3bSJed Brown               nleavesExpanded++;
13070a96aa3bSJed Brown             }
13080a96aa3bSJed Brown           }
13099566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&coarseToPreFineNew));
13100a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
13119566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,leavesNew,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES));
13120a96aa3bSJed Brown           } else {
13139566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
13149566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,NULL,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES));
13150a96aa3bSJed Brown           }
13169566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesExpanded));
13179566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseToPreFine));
13180a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
13190a96aa3bSJed Brown         }
13200a96aa3bSJed Brown       }
13210a96aa3bSJed Brown     }
13220a96aa3bSJed Brown   }
13230a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
13240a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
13250a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
13269566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&ctx.anyChange,&(pforest->adaptivitySuccess),1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm)));
13279566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,NULL));
13280a96aa3bSJed Brown   PetscFunctionReturn(0);
13290a96aa3bSJed Brown }
13300a96aa3bSJed Brown 
13310a96aa3bSJed Brown #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
13320a96aa3bSJed Brown static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success)
13330a96aa3bSJed Brown {
13340a96aa3bSJed Brown   DM_Forest         *forest;
13350a96aa3bSJed Brown   DM_Forest_pforest *pforest;
13360a96aa3bSJed Brown 
13370a96aa3bSJed Brown   PetscFunctionBegin;
13380a96aa3bSJed Brown   forest   = (DM_Forest *) dm->data;
13390a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *) forest->data;
13400a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
13410a96aa3bSJed Brown   PetscFunctionReturn(0);
13420a96aa3bSJed Brown }
13430a96aa3bSJed Brown 
13440a96aa3bSJed Brown #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
13450a96aa3bSJed Brown static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer)
13460a96aa3bSJed Brown {
13470a96aa3bSJed Brown   DM             dm = (DM) odm;
13480a96aa3bSJed Brown 
13490a96aa3bSJed Brown   PetscFunctionBegin;
13500a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13510a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13529566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13530a96aa3bSJed Brown   switch (viewer->format) {
13540a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
13550a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO:
13560a96aa3bSJed Brown   {
13570a96aa3bSJed Brown     PetscInt   dim;
13580a96aa3bSJed Brown     const char *name;
13590a96aa3bSJed Brown 
13609566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
13619566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
136263a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "Forest %s in %" PetscInt_FMT " dimensions:\n", name, dim));
136363a3b9bcSJacob Faibussowitsch     else      PetscCall(PetscViewerASCIIPrintf(viewer, "Forest in %" PetscInt_FMT " dimensions:\n", dim));
13640a96aa3bSJed Brown   }
13650a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
13660a96aa3bSJed Brown   case PETSC_VIEWER_LOAD_BALANCE:
13670a96aa3bSJed Brown   {
13680a96aa3bSJed Brown     DM plex;
13690a96aa3bSJed Brown 
13709566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dm, &plex));
13719566063dSJacob Faibussowitsch     PetscCall(DMView(plex, viewer));
13720a96aa3bSJed Brown   }
13730a96aa3bSJed Brown   break;
137498921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13750a96aa3bSJed Brown   }
13760a96aa3bSJed Brown   PetscFunctionReturn(0);
13770a96aa3bSJed Brown }
13780a96aa3bSJed Brown 
13790a96aa3bSJed Brown #define DMView_VTK_pforest _append_pforest(DMView_VTK)
13800a96aa3bSJed Brown static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer)
13810a96aa3bSJed Brown {
13820a96aa3bSJed Brown   DM                dm       = (DM) odm;
13830a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
13840a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
13850a96aa3bSJed Brown   PetscBool         isvtk;
13860a96aa3bSJed Brown   PetscReal         vtkScale = 1. - PETSC_MACHINE_EPSILON;
13870a96aa3bSJed Brown   PetscViewer_VTK   *vtk     = (PetscViewer_VTK*)viewer->data;
13880a96aa3bSJed Brown   const char        *name;
13890a96aa3bSJed Brown   char              *filenameStrip = NULL;
13900a96aa3bSJed Brown   PetscBool         hasExt;
13910a96aa3bSJed Brown   size_t            len;
13920a96aa3bSJed Brown   p4est_geometry_t  *geom;
13930a96aa3bSJed Brown 
13940a96aa3bSJed Brown   PetscFunctionBegin;
13950a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13960a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13979566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13980a96aa3bSJed Brown   geom = pforest->topo->geom;
13999566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk));
140028b400f6SJacob Faibussowitsch   PetscCheck(isvtk,PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
14010a96aa3bSJed Brown   switch (viewer->format) {
14020a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
140328b400f6SJacob Faibussowitsch     PetscCheck(pforest->forest,PetscObjectComm(odm),PETSC_ERR_ARG_WRONG,"DM has not been setup with a valid forest");
14040a96aa3bSJed Brown     name = vtk->filename;
14059566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(name,&len));
14069566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(name+len-4,".vtu",&hasExt));
14070a96aa3bSJed Brown     if (hasExt) {
14089566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(name,&filenameStrip));
14090a96aa3bSJed Brown       filenameStrip[len-4]='\0';
14100a96aa3bSJed Brown       name                = filenameStrip;
14110a96aa3bSJed Brown     }
14120a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4estReturn(geom,p4est_geometry_new_connectivity,(pforest->topo->conn));
14130a96aa3bSJed Brown     {
14140a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
14150a96aa3bSJed Brown       int                 footerr;
14160a96aa3bSJed Brown 
14170a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_context_new,(pforest->forest,name));
14180a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_geom,(pvtk,geom));
14190a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_scale,(pvtk,(double)vtkScale));
14200a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_header,(pvtk));
142128b400f6SJacob Faibussowitsch       PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_header() failed");
14220a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_cell_dataf,(pvtk,
14230a96aa3bSJed Brown                                                                  1, /* write tree */
14240a96aa3bSJed Brown                                                                  1, /* write level */
14250a96aa3bSJed Brown                                                                  1, /* write rank */
14260a96aa3bSJed Brown                                                                  0, /* do not wrap rank */
14270a96aa3bSJed Brown                                                                  0, /* no scalar fields */
14280a96aa3bSJed Brown                                                                  0, /* no vector fields */
14290a96aa3bSJed Brown                                                                  pvtk));
143028b400f6SJacob Faibussowitsch       PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_cell_dataf() failed");
14310a96aa3bSJed Brown       PetscStackCallP4estReturn(footerr,p4est_vtk_write_footer,(pvtk));
143228b400f6SJacob Faibussowitsch       PetscCheck(!footerr,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_footer() failed");
14330a96aa3bSJed Brown     }
14340a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4est(p4est_geometry_destroy,(geom));
14359566063dSJacob Faibussowitsch     PetscCall(PetscFree(filenameStrip));
14360a96aa3bSJed Brown     break;
143798921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
14380a96aa3bSJed Brown   }
14390a96aa3bSJed Brown   PetscFunctionReturn(0);
14400a96aa3bSJed Brown }
14410a96aa3bSJed Brown 
14420a96aa3bSJed Brown #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
14430a96aa3bSJed Brown static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer)
14440a96aa3bSJed Brown {
14450a96aa3bSJed Brown   DM             plex;
14460a96aa3bSJed Brown 
14470a96aa3bSJed Brown   PetscFunctionBegin;
14489566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14499566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14509566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14510a96aa3bSJed Brown   PetscFunctionReturn(0);
14520a96aa3bSJed Brown }
14530a96aa3bSJed Brown 
14540a96aa3bSJed Brown #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
14550a96aa3bSJed Brown static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer)
14560a96aa3bSJed Brown {
14570a96aa3bSJed Brown   DM             plex;
14580a96aa3bSJed Brown 
14590a96aa3bSJed Brown   PetscFunctionBegin;
14609566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14619566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14629566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14630a96aa3bSJed Brown   PetscFunctionReturn(0);
14640a96aa3bSJed Brown }
14650a96aa3bSJed Brown 
14660a96aa3bSJed Brown #define DMView_pforest _append_pforest(DMView)
14670a96aa3bSJed Brown static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer)
14680a96aa3bSJed Brown {
14690a96aa3bSJed Brown   PetscBool      isascii, isvtk, ishdf5, isglvis;
14700a96aa3bSJed Brown 
14710a96aa3bSJed Brown   PetscFunctionBegin;
14720a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14730a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
14749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii));
14759566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk));
14769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5));
14779566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis));
14780a96aa3bSJed Brown   if (isascii) {
14799566063dSJacob Faibussowitsch     PetscCall(DMView_ASCII_pforest((PetscObject) dm,viewer));
14800a96aa3bSJed Brown   } else if (isvtk) {
14819566063dSJacob Faibussowitsch     PetscCall(DMView_VTK_pforest((PetscObject) dm,viewer));
14820a96aa3bSJed Brown   } else if (ishdf5) {
14839566063dSJacob Faibussowitsch     PetscCall(DMView_HDF5_pforest(dm, viewer));
14840a96aa3bSJed Brown   } else if (isglvis) {
14859566063dSJacob Faibussowitsch     PetscCall(DMView_GLVis_pforest(dm, viewer));
14860a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject) dm),PETSC_ERR_SUP,"Viewer not supported (not VTK, HDF5, or GLVis)");
14870a96aa3bSJed Brown   PetscFunctionReturn(0);
14880a96aa3bSJed Brown }
14890a96aa3bSJed Brown 
14900a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq)
14910a96aa3bSJed Brown {
14920a96aa3bSJed Brown   PetscInt       *ttf, f, t, g, count;
14930a96aa3bSJed Brown   PetscInt       numFacets;
14940a96aa3bSJed Brown 
14950a96aa3bSJed Brown   PetscFunctionBegin;
14960a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
14979566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFacets,&ttf));
14980a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
14990a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
15000a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
15010a96aa3bSJed Brown       if (ttf[g] == -1) {
15020a96aa3bSJed Brown         PetscInt ng;
15030a96aa3bSJed Brown 
15040a96aa3bSJed Brown         ttf[g]  = count++;
15050a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
15060a96aa3bSJed Brown         ttf[ng] = ttf[g];
15070a96aa3bSJed Brown       }
15080a96aa3bSJed Brown     }
15090a96aa3bSJed Brown   }
15100a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
15110a96aa3bSJed Brown   PetscFunctionReturn(0);
15120a96aa3bSJed Brown }
15130a96aa3bSJed Brown 
15140a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq)
15150a96aa3bSJed Brown {
15160a96aa3bSJed Brown   p4est_topidx_t       numTrees, numVerts, numCorns, numCtt;
15170a96aa3bSJed Brown   PetscSection         ctt;
15180a96aa3bSJed Brown #if defined(P4_TO_P8)
15190a96aa3bSJed Brown   p4est_topidx_t       numEdges, numEtt;
15200a96aa3bSJed Brown   PetscSection         ett;
15210a96aa3bSJed Brown   PetscInt             eStart, eEnd, e, ettSize;
15220a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES + P8EST_EDGES;
15230a96aa3bSJed Brown   PetscInt             edgeOff = 1 + P4EST_FACES;
15240a96aa3bSJed Brown #else
15250a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES;
15260a96aa3bSJed Brown #endif
15270a96aa3bSJed Brown   p4est_connectivity_t *conn;
15280a96aa3bSJed Brown   PetscInt             cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
15290a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
15300a96aa3bSJed Brown   PetscInt             *ttf;
15310a96aa3bSJed Brown 
15320a96aa3bSJed Brown   PetscFunctionBegin;
15330a96aa3bSJed Brown   /* 1: count objects, allocate */
15349566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd));
15359566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cEnd-cStart,&numTrees));
15360a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
15379566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd));
15389566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(vEnd-vStart,&numCorns));
15399566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&ctt));
15409566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ctt,vStart,vEnd));
15410a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
15420a96aa3bSJed Brown     PetscInt s;
15430a96aa3bSJed Brown 
15449566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
15450a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15460a96aa3bSJed Brown       PetscInt p = star[2*s];
15470a96aa3bSJed Brown 
15480a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15490a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
15500a96aa3bSJed Brown          * only protects against periodicity problems */
15519566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
155263a3b9bcSJacob Faibussowitsch         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell %" PetscInt_FMT " with wrong closure size %" PetscInt_FMT " != %d", p, closureSize, P4EST_INSUL);
15530a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
15540a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
15550a96aa3bSJed Brown 
15561dca8a05SBarry Smith           PetscCheck(cellVert >= vStart && cellVert < vEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: vertices");
15570a96aa3bSJed Brown           if (cellVert == v) {
15589566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(ctt,v,1));
15590a96aa3bSJed Brown           }
15600a96aa3bSJed Brown         }
15619566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15620a96aa3bSJed Brown       }
15630a96aa3bSJed Brown     }
15649566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
15650a96aa3bSJed Brown   }
15669566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ctt));
15679566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ctt,&cttSize));
15689566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cttSize,&numCtt));
15690a96aa3bSJed Brown #if defined(P4_TO_P8)
15709566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,P4EST_DIM-1,&eStart,&eEnd));
15719566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(eEnd-eStart,&numEdges));
15729566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&ett));
15739566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ett,eStart,eEnd));
15740a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
15750a96aa3bSJed Brown     PetscInt s;
15760a96aa3bSJed Brown 
15779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
15780a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15790a96aa3bSJed Brown       PetscInt p = star[2*s];
15800a96aa3bSJed Brown 
15810a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15820a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
15830a96aa3bSJed Brown          * only protects against periodicity problems */
15849566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
158508401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell with wrong closure size");
15860a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
15870a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
15880a96aa3bSJed Brown 
15891dca8a05SBarry Smith           PetscCheck(cellEdge >= eStart && cellEdge < eEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: edges");
15900a96aa3bSJed Brown           if (cellEdge == e) {
15919566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(ett,e,1));
15920a96aa3bSJed Brown           }
15930a96aa3bSJed Brown         }
15949566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15950a96aa3bSJed Brown       }
15960a96aa3bSJed Brown     }
15979566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
15980a96aa3bSJed Brown   }
15999566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ett));
16009566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ett,&ettSize));
16019566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(ettSize,&numEtt));
16020a96aa3bSJed Brown 
16030a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
16040a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p8est_connectivity_new,(numVerts,numTrees,numEdges,numEtt,numCorns,numCtt));
16050a96aa3bSJed Brown #else
16060a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p4est_connectivity_new,(numVerts,numTrees,numCorns,numCtt));
16070a96aa3bSJed Brown #endif
16080a96aa3bSJed Brown 
16090a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
16109566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,1,&fStart,&fEnd));
16119566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((cEnd-cStart) * P4EST_FACES,&ttf));
16120a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
16130a96aa3bSJed Brown     PetscInt       numSupp, s;
16140a96aa3bSJed Brown     PetscInt       myFace[2] = {-1, -1};
16150a96aa3bSJed Brown     PetscInt       myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
16160a96aa3bSJed Brown     const PetscInt *supp;
16170a96aa3bSJed Brown 
16189566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numSupp));
16191dca8a05SBarry Smith     PetscCheck(numSupp == 1 || numSupp == 2,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"point %" PetscInt_FMT " has facet with %" PetscInt_FMT " sides: must be 1 or 2 (boundary or conformal)",f,numSupp);
16209566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &supp));
16210a96aa3bSJed Brown 
16220a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16230a96aa3bSJed Brown       PetscInt p = supp[s];
16240a96aa3bSJed Brown 
16250a96aa3bSJed Brown       if (p >= cEnd) {
16260a96aa3bSJed Brown         numSupp--;
16270a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
16280a96aa3bSJed Brown         break;
16290a96aa3bSJed Brown       }
16300a96aa3bSJed Brown     }
16310a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16320a96aa3bSJed Brown       PetscInt       p = supp[s], i;
16330a96aa3bSJed Brown       PetscInt       numCone;
16340a96aa3bSJed Brown       DMPolytopeType ct;
16350a96aa3bSJed Brown       const PetscInt *cone;
16360a96aa3bSJed Brown       const PetscInt *ornt;
16370a96aa3bSJed Brown       PetscInt       orient = PETSC_MIN_INT;
16380a96aa3bSJed Brown 
16399566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &numCone));
164063a3b9bcSJacob Faibussowitsch       PetscCheck(numCone == P4EST_FACES,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %" PetscInt_FMT " has %" PetscInt_FMT " facets, expect %d",p,numCone,P4EST_FACES);
16419566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
16429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[0], &ct));
16439566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
16440a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
16450a96aa3bSJed Brown         if (cone[i] == f) {
16460a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
16470a96aa3bSJed Brown           break;
16480a96aa3bSJed Brown         }
16490a96aa3bSJed Brown       }
165063a3b9bcSJacob Faibussowitsch       PetscCheck(i < P4EST_FACES,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %" PetscInt_FMT " faced %" PetscInt_FMT " mismatch",p,f);
16510a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
16520a96aa3bSJed Brown         DMPolytopeType ct;
16539566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
165463a3b9bcSJacob Faibussowitsch         SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %" PetscInt_FMT " (%s) should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")",p,DMPolytopeTypes[ct],cStart,cEnd);
16550a96aa3bSJed Brown       }
16560a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
16570a96aa3bSJed Brown       if (numSupp == 1) {
16580a96aa3bSJed Brown         /* boundary faces indicated by self reference */
16590a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
16600a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t) PetscFaceToP4estFace[i];
16610a96aa3bSJed Brown       } else {
16620a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16630a96aa3bSJed Brown 
16640a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
16650a96aa3bSJed Brown         myFace[s] = PetscFaceToP4estFace[i];
16660a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
16670a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
16680a96aa3bSJed Brown         myOrnt[s] = DihedralCompose(N,orient,DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
16690a96aa3bSJed Brown       }
16700a96aa3bSJed Brown     }
16710a96aa3bSJed Brown     if (numSupp == 2) {
16720a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
16730a96aa3bSJed Brown         PetscInt       p = supp[s];
16740a96aa3bSJed Brown         PetscInt       orntAtoB;
16750a96aa3bSJed Brown         PetscInt       p4estOrient;
16760a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16770a96aa3bSJed Brown 
16780a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
16790a96aa3bSJed Brown          * permutation of this cell-facet's cone */
16800a96aa3bSJed Brown         orntAtoB = DihedralCompose(N,DihedralInvert(N,myOrnt[1-s]),myOrnt[s]);
16810a96aa3bSJed Brown 
16820a96aa3bSJed Brown         /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
16830a96aa3bSJed Brown          * vertices around facet) */
16840a96aa3bSJed Brown #if !defined(P4_TO_P8)
16850a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
16860a96aa3bSJed Brown #else
16870a96aa3bSJed Brown         {
16880a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
16890a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
16900a96aa3bSJed Brown 
16910a96aa3bSJed Brown                                                                                            /* swap bits */
16920a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
16930a96aa3bSJed Brown         }
16940a96aa3bSJed Brown #endif
16950a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
16960a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
16970a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t) myFace[1 - s] + p4estOrient * P4EST_FACES;
16980a96aa3bSJed Brown       }
16990a96aa3bSJed Brown     }
17000a96aa3bSJed Brown   }
17010a96aa3bSJed Brown 
17020a96aa3bSJed Brown #if defined(P4_TO_P8)
17030a96aa3bSJed Brown   /* 3: visit every edge */
17040a96aa3bSJed Brown   conn->ett_offset[0] = 0;
17050a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
17060a96aa3bSJed Brown     PetscInt off, s;
17070a96aa3bSJed Brown 
17089566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ett,e,&off));
17090a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t) off;
17109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
17110a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17120a96aa3bSJed Brown       PetscInt p = star[2 * s];
17130a96aa3bSJed Brown 
17140a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17159566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
171608401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
17170a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
17180a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
17190a96aa3bSJed Brown           PetscInt cellOrnt = closure[2 * (c + edgeOff) + 1];
17200a96aa3bSJed Brown           DMPolytopeType ct;
17210a96aa3bSJed Brown 
17229566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cellEdge, &ct));
17230a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
17240a96aa3bSJed Brown           if (cellEdge == e) {
17250a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
17260a96aa3bSJed Brown             PetscInt totalOrient;
17270a96aa3bSJed Brown 
17280a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
17290a96aa3bSJed Brown             totalOrient = DihedralCompose(2,cellOrnt,DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
17300a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
17310a96aa3bSJed Brown             totalOrient             = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
17320a96aa3bSJed Brown             conn->edge_to_tree[off] = (p4est_locidx_t) (p - cStart);
17330a96aa3bSJed Brown             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standart (see
17340a96aa3bSJed Brown              * p8est_connectivity.h) */
17350a96aa3bSJed Brown             conn->edge_to_edge[off++] = (int8_t) p4estEdge + P8EST_EDGES * totalOrient;
17360a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
17370a96aa3bSJed Brown           }
17380a96aa3bSJed Brown         }
17399566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17400a96aa3bSJed Brown       }
17410a96aa3bSJed Brown     }
17429566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
17430a96aa3bSJed Brown   }
17449566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ett));
17450a96aa3bSJed Brown #endif
17460a96aa3bSJed Brown 
17470a96aa3bSJed Brown   /* 4: visit every vertex */
17480a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
17490a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
17500a96aa3bSJed Brown     PetscInt off, s;
17510a96aa3bSJed Brown 
17529566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ctt,v,&off));
17530a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t) off;
17549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
17550a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17560a96aa3bSJed Brown       PetscInt p = star[2 * s];
17570a96aa3bSJed Brown 
17580a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17599566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
176008401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
17610a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
17620a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
17630a96aa3bSJed Brown 
17640a96aa3bSJed Brown           if (cellVert == v) {
17650a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
17660a96aa3bSJed Brown 
17670a96aa3bSJed Brown             conn->corner_to_tree[off]     = (p4est_locidx_t) (p - cStart);
17680a96aa3bSJed Brown             conn->corner_to_corner[off++] = (int8_t) p4estVert;
17690a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
17700a96aa3bSJed Brown           }
17710a96aa3bSJed Brown         }
17729566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17730a96aa3bSJed Brown       }
17740a96aa3bSJed Brown     }
17759566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
17760a96aa3bSJed Brown   }
17779566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ctt));
17780a96aa3bSJed Brown 
17790a96aa3bSJed Brown   /* 5: Compute the coordinates */
17800a96aa3bSJed Brown   {
17810a96aa3bSJed Brown     PetscInt coordDim;
17820a96aa3bSJed Brown 
17839566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
17846858538eSMatthew G. Knepley     PetscCall(DMGetCoordinatesLocalSetUp(dm));
17850a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
17860a96aa3bSJed Brown       PetscInt           dof;
17876858538eSMatthew G. Knepley       PetscBool          isDG;
17880a96aa3bSJed Brown       PetscScalar       *cellCoords = NULL;
17896858538eSMatthew G. Knepley       const PetscScalar *array;
17900a96aa3bSJed Brown 
17916858538eSMatthew G. Knepley       PetscCall(DMPlexGetCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
17926858538eSMatthew G. Knepley       PetscCheck(dof == P4EST_CHILDREN * coordDim, PETSC_COMM_SELF, PETSC_ERR_ARG_WRONG, "Need coordinates at the corners: (dof) %" PetscInt_FMT " != %d * %" PetscInt_FMT " (sdim)", dof, P4EST_CHILDREN, coordDim);
17930a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
17940a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
17950a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
17960a96aa3bSJed Brown 
17970a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
17980a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
17990a96aa3bSJed Brown         for (i = 0; i < 3; i++)   conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
18000a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
18010a96aa3bSJed Brown       }
18026858538eSMatthew G. Knepley       PetscCall(DMPlexRestoreCellCoordinates(dm, c, &isDG, &dof, &array, &cellCoords));
18030a96aa3bSJed Brown     }
18040a96aa3bSJed Brown   }
18050a96aa3bSJed Brown 
18060a96aa3bSJed Brown #if defined(P4EST_ENABLE_DEBUG)
180708401ef6SPierre Jolivet   PetscCheck(p4est_connectivity_is_valid(conn),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Plex to p4est conversion failed");
18080a96aa3bSJed Brown #endif
18090a96aa3bSJed Brown 
18100a96aa3bSJed Brown   *connOut = conn;
18110a96aa3bSJed Brown 
18120a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
18130a96aa3bSJed Brown 
18140a96aa3bSJed Brown   PetscFunctionReturn(0);
18150a96aa3bSJed Brown }
18160a96aa3bSJed Brown 
18170a96aa3bSJed Brown static PetscErrorCode locidx_to_PetscInt(sc_array_t * array)
18180a96aa3bSJed Brown {
18190a96aa3bSJed Brown   sc_array_t *newarray;
18200a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18210a96aa3bSJed Brown 
18220a96aa3bSJed Brown   PetscFunctionBegin;
182308401ef6SPierre Jolivet   PetscCheck(array->elem_size == sizeof(p4est_locidx_t),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
18240a96aa3bSJed Brown 
18250a96aa3bSJed Brown   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(0);
18260a96aa3bSJed Brown 
18270a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscInt), array->elem_count);
18280a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18290a96aa3bSJed Brown     p4est_locidx_t il  = *((p4est_locidx_t*) sc_array_index (array, zz));
18300a96aa3bSJed Brown     PetscInt       *ip = (PetscInt*) sc_array_index (newarray, zz);
18310a96aa3bSJed Brown 
18320a96aa3bSJed Brown     *ip = (PetscInt) il;
18330a96aa3bSJed Brown   }
18340a96aa3bSJed Brown 
18350a96aa3bSJed Brown   sc_array_reset (array);
18360a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscInt), count);
18370a96aa3bSJed Brown   sc_array_copy (array, newarray);
18380a96aa3bSJed Brown   sc_array_destroy (newarray);
18390a96aa3bSJed Brown   PetscFunctionReturn(0);
18400a96aa3bSJed Brown }
18410a96aa3bSJed Brown 
18420a96aa3bSJed Brown static PetscErrorCode coords_double_to_PetscScalar(sc_array_t * array, PetscInt dim)
18430a96aa3bSJed Brown {
18440a96aa3bSJed Brown   sc_array_t *newarray;
18450a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18460a96aa3bSJed Brown 
18470a96aa3bSJed Brown   PetscFunctionBegin;
18481dca8a05SBarry Smith   PetscCheck(array->elem_size == 3 * sizeof(double),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong coordinate size");
18490a96aa3bSJed Brown #if !defined(PETSC_USE_COMPLEX)
18500a96aa3bSJed Brown   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(0);
18510a96aa3bSJed Brown #endif
18520a96aa3bSJed Brown 
18530a96aa3bSJed Brown   newarray = sc_array_new_size (dim * sizeof(PetscScalar), array->elem_count);
18540a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18550a96aa3bSJed Brown     int         i;
18560a96aa3bSJed Brown     double      *id = (double*) sc_array_index (array, zz);
18570a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar*) sc_array_index (newarray, zz);
18580a96aa3bSJed Brown 
18590a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
18600a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim,3); i++) ip[i] = (PetscScalar) id[i];
18610a96aa3bSJed Brown   }
18620a96aa3bSJed Brown 
18630a96aa3bSJed Brown   sc_array_reset (array);
18640a96aa3bSJed Brown   sc_array_init_size (array, dim * sizeof(PetscScalar), count);
18650a96aa3bSJed Brown   sc_array_copy (array, newarray);
18660a96aa3bSJed Brown   sc_array_destroy (newarray);
18670a96aa3bSJed Brown   PetscFunctionReturn(0);
18680a96aa3bSJed Brown }
18690a96aa3bSJed Brown 
18700a96aa3bSJed Brown static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t * array)
18710a96aa3bSJed Brown {
18720a96aa3bSJed Brown   sc_array_t *newarray;
18730a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18740a96aa3bSJed Brown 
18750a96aa3bSJed Brown   PetscFunctionBegin;
18761dca8a05SBarry Smith   PetscCheck(array->elem_size == 2 * sizeof(p4est_locidx_t),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
18770a96aa3bSJed Brown 
18780a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscSFNode), array->elem_count);
18790a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18800a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t*) sc_array_index (array, zz);
18810a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode*) sc_array_index (newarray, zz);
18820a96aa3bSJed Brown 
18830a96aa3bSJed Brown     ip->rank  = (PetscInt) il[0];
18840a96aa3bSJed Brown     ip->index = (PetscInt) il[1];
18850a96aa3bSJed Brown   }
18860a96aa3bSJed Brown 
18870a96aa3bSJed Brown   sc_array_reset (array);
18880a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscSFNode), count);
18890a96aa3bSJed Brown   sc_array_copy (array, newarray);
18900a96aa3bSJed Brown   sc_array_destroy (newarray);
18910a96aa3bSJed Brown   PetscFunctionReturn(0);
18920a96aa3bSJed Brown }
18930a96aa3bSJed Brown 
18940a96aa3bSJed Brown static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM * plex)
18950a96aa3bSJed Brown {
18960a96aa3bSJed Brown   PetscFunctionBegin;
18970a96aa3bSJed Brown   {
18980a96aa3bSJed Brown     sc_array_t     *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
18990a96aa3bSJed Brown     sc_array_t     *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
19000a96aa3bSJed Brown     sc_array_t     *cones             = sc_array_new(sizeof(p4est_locidx_t));
19010a96aa3bSJed Brown     sc_array_t     *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
19020a96aa3bSJed Brown     sc_array_t     *coords            = sc_array_new(3 * sizeof(double));
19030a96aa3bSJed Brown     sc_array_t     *children          = sc_array_new(sizeof(p4est_locidx_t));
19040a96aa3bSJed Brown     sc_array_t     *parents           = sc_array_new(sizeof(p4est_locidx_t));
19050a96aa3bSJed Brown     sc_array_t     *childids          = sc_array_new(sizeof(p4est_locidx_t));
19060a96aa3bSJed Brown     sc_array_t     *leaves            = sc_array_new(sizeof(p4est_locidx_t));
19070a96aa3bSJed Brown     sc_array_t     *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
19080a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
19090a96aa3bSJed Brown 
19100a96aa3bSJed 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));
19110a96aa3bSJed Brown 
19129566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
19139566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
19149566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
19159566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
19169566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, P4EST_DIM));
19170a96aa3bSJed Brown 
19189566063dSJacob Faibussowitsch     PetscCall(DMPlexCreate(PETSC_COMM_SELF,plex));
19199566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(*plex,P4EST_DIM));
19209566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(*plex,P4EST_DIM,(PetscInt*)points_per_dim->array,(PetscInt*)cone_sizes->array,(PetscInt*)cones->array,(PetscInt*)cone_orientations->array,(PetscScalar*)coords->array));
19219566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(*plex));
19220a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
19230a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
19240a96aa3bSJed Brown     sc_array_destroy (cones);
19250a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
19260a96aa3bSJed Brown     sc_array_destroy (coords);
19270a96aa3bSJed Brown     sc_array_destroy (children);
19280a96aa3bSJed Brown     sc_array_destroy (parents);
19290a96aa3bSJed Brown     sc_array_destroy (childids);
19300a96aa3bSJed Brown     sc_array_destroy (leaves);
19310a96aa3bSJed Brown     sc_array_destroy (remotes);
19320a96aa3bSJed Brown   }
19330a96aa3bSJed Brown   PetscFunctionReturn(0);
19340a96aa3bSJed Brown }
19350a96aa3bSJed Brown 
19360a96aa3bSJed Brown #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
19370a96aa3bSJed Brown static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB,PetscInt *childB)
19380a96aa3bSJed Brown {
19390a96aa3bSJed Brown   PetscInt       coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
19400a96aa3bSJed Brown 
19410a96aa3bSJed Brown   PetscFunctionBegin;
19420a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
19430a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
19440a96aa3bSJed Brown     if (childB) *childB = childA;
19450a96aa3bSJed Brown     PetscFunctionReturn(0);
19460a96aa3bSJed Brown   }
19479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd));
19486aad120cSJose E. Roman   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invariant under rotation */
19490a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
19500a96aa3bSJed Brown     if (childB) *childB = childA;
19510a96aa3bSJed Brown     PetscFunctionReturn(0);
19520a96aa3bSJed Brown   }
19530a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
19549566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd));
19550a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
19560a96aa3bSJed Brown   }
195763a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %" PetscInt_FMT "-cells",dim);
195828b400f6SJacob Faibussowitsch   PetscCheck(dim,PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
19590a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
19600a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
19610a96aa3bSJed Brown     PetscInt       size, i, sA = -1, sB, sOrientB, sConeSize;
19620a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
19630a96aa3bSJed Brown 
19649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm,childA,&size));
19659566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm,childA,&supp));
19660a96aa3bSJed Brown 
19670a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
19680a96aa3bSJed Brown     for (i = 0; i < size; i++) {
19690a96aa3bSJed Brown       PetscInt sParent;
19700a96aa3bSJed Brown 
19710a96aa3bSJed Brown       sA = supp[i];
19720a96aa3bSJed Brown       if (sA == parent) continue;
19739566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,sA,&sParent,NULL));
19740a96aa3bSJed Brown       if (sParent == parent) break;
19750a96aa3bSJed Brown     }
197608401ef6SPierre Jolivet     PetscCheck(i != size,PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
19770a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
19780a96aa3bSJed Brown      * parentOrientB */
19799566063dSJacob Faibussowitsch     PetscCall(DMReferenceTreeGetChildSymmetry_pforest(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB));
19809566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,sA,&sConeSize));
19819566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sA,&coneA));
19829566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sB,&coneB));
19839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sA,&oA));
19849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sB,&oB));
19850a96aa3bSJed Brown     /* step through the cone of sA in natural order */
19860a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
19870a96aa3bSJed Brown       if (coneA[i] == childA) {
19880a96aa3bSJed Brown         /* if childA is at position i in coneA,
19890a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
19900a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
19910a96aa3bSJed Brown         if (childB) *childB = coneB[j];
19920a96aa3bSJed Brown         if (childOrientB) {
19930a96aa3bSJed Brown           DMPolytopeType ct;
19940a96aa3bSJed Brown           PetscInt       oBtrue;
19950a96aa3bSJed Brown 
19969566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,childA,&coneSize));
19970a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
19981dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
19990a96aa3bSJed Brown           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
20000a96aa3bSJed Brown           /* we may have to flip an edge */
20010a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
20020a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
20030a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize,DMPolytopeConvertNewOrientation_Internal(ct, oA[i]),oBtrue);
20040a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
20050a96aa3bSJed Brown         }
20060a96aa3bSJed Brown         break;
20070a96aa3bSJed Brown       }
20080a96aa3bSJed Brown     }
200908401ef6SPierre Jolivet     PetscCheck(i != sConeSize,PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
20100a96aa3bSJed Brown     PetscFunctionReturn(0);
20110a96aa3bSJed Brown   }
20120a96aa3bSJed Brown   /* get the cone size and symmetry swap */
20139566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm,parent,&coneSize));
20140a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
20150a96aa3bSJed Brown   if (dim == 2) {
20160a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
20170a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
20180a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
20190a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
20200a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
20210a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
20220a96aa3bSJed Brown   } else {
20230a96aa3bSJed Brown     oAvert     = parentOrientA;
20240a96aa3bSJed Brown     oBvert     = parentOrientB;
20250a96aa3bSJed Brown     ABswapVert = ABswap;
20260a96aa3bSJed Brown   }
20270a96aa3bSJed Brown   if (childB) {
20280a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
20290a96aa3bSJed Brown     PetscInt       p, posA = -1, numChildren, i;
20300a96aa3bSJed Brown     const PetscInt *children;
20310a96aa3bSJed Brown 
20320a96aa3bSJed Brown     /* count which position the child is in */
20339566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm,parent,&numChildren,&children));
20340a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
20350a96aa3bSJed Brown       p = children[i];
20360a96aa3bSJed Brown       if (p == childA) {
20370a96aa3bSJed Brown         if (dim == 1) {
20380a96aa3bSJed Brown           posA = i;
20390a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
20400a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
20410a96aa3bSJed Brown         }
20420a96aa3bSJed Brown         break;
20430a96aa3bSJed Brown       }
20440a96aa3bSJed Brown     }
20450a96aa3bSJed Brown     if (posA >= coneSize) {
20460a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not find childA in children of parent");
20470a96aa3bSJed Brown     } else {
20480a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
20490a96aa3bSJed Brown       PetscInt posB, childIdB;
20500a96aa3bSJed Brown 
20510a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
20520a96aa3bSJed Brown       if (dim == 1) {
20530a96aa3bSJed Brown         childIdB = posB;
20540a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
20550a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
20560a96aa3bSJed Brown       }
20570a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
20580a96aa3bSJed Brown     }
20590a96aa3bSJed Brown   }
20600a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
20610a96aa3bSJed Brown   PetscFunctionReturn(0);
20620a96aa3bSJed Brown }
20630a96aa3bSJed Brown 
20640a96aa3bSJed Brown #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
20650a96aa3bSJed Brown static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm)
20660a96aa3bSJed Brown {
20670a96aa3bSJed Brown   p4est_connectivity_t *refcube;
20680a96aa3bSJed Brown   p4est_t              *root, *refined;
20690a96aa3bSJed Brown   DM                   dmRoot, dmRefined;
20700a96aa3bSJed Brown   DM_Plex              *mesh;
20710a96aa3bSJed Brown   PetscMPIInt          rank;
2072*66c0a4b5SToby Isaac #if defined(PETSC_HAVE_MPIUNI)
2073*66c0a4b5SToby Isaac   sc_MPI_Comm          comm_self = sc_MPI_COMM_SELF;
2074*66c0a4b5SToby Isaac #else
2075*66c0a4b5SToby Isaac   MPI_Comm             comm_self = PETSC_COMM_SELF;
2076*66c0a4b5SToby Isaac #endif
20770a96aa3bSJed Brown 
20780a96aa3bSJed Brown   PetscFunctionBegin;
20790a96aa3bSJed Brown   PetscStackCallP4estReturn(refcube,p4est_connectivity_new_byname,("unit"));
20800a96aa3bSJed Brown   { /* [-1,1]^d geometry */
20810a96aa3bSJed Brown     PetscInt i, j;
20820a96aa3bSJed Brown 
20830a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
20840a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
20850a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
20860a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
20870a96aa3bSJed Brown       }
20880a96aa3bSJed Brown     }
20890a96aa3bSJed Brown   }
2090*66c0a4b5SToby Isaac   PetscStackCallP4estReturn(root,p4est_new,(comm_self,refcube,0,NULL,NULL));
2091*66c0a4b5SToby Isaac   PetscStackCallP4estReturn(refined,p4est_new_ext,(comm_self,refcube,0,1,1,0,NULL,NULL));
20929566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(root,&dmRoot));
20939566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(refined,&dmRefined));
20940a96aa3bSJed Brown   {
20950a96aa3bSJed Brown #if !defined(P4_TO_P8)
20960a96aa3bSJed Brown     PetscInt nPoints  = 25;
20970a96aa3bSJed Brown     PetscInt perm[25] = {0, 1, 2, 3,
20980a96aa3bSJed Brown                           4, 12, 8, 14,
20990a96aa3bSJed Brown                               6, 9, 15,
21000a96aa3bSJed Brown                           5, 13,    10,
21010a96aa3bSJed Brown                               7,    11,
21020a96aa3bSJed Brown                          16, 22, 20, 24,
21030a96aa3bSJed Brown                              17,     21,
21040a96aa3bSJed Brown                                  18, 23,
21050a96aa3bSJed Brown                                      19};
21060a96aa3bSJed Brown     PetscInt ident[25] = {0, 0, 0, 0,
21070a96aa3bSJed Brown                           1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0,
21080a96aa3bSJed Brown                           5, 6, 7, 8, 1, 2, 3, 4, 0};
21090a96aa3bSJed Brown #else
21100a96aa3bSJed Brown     PetscInt nPoints   = 125;
21110a96aa3bSJed Brown     PetscInt perm[125] = {0, 1, 2, 3, 4, 5, 6, 7,
21120a96aa3bSJed Brown                            8, 32, 16, 36, 24, 40,
21130a96aa3bSJed Brown                               12, 17, 37, 25, 41,
21140a96aa3bSJed Brown                            9, 33,     20, 26, 42,
21150a96aa3bSJed Brown                               13,     21, 27, 43,
21160a96aa3bSJed Brown                           10, 34, 18, 38,     28,
21170a96aa3bSJed Brown                               14, 19, 39,     29,
21180a96aa3bSJed Brown                           11, 35,     22,     30,
21190a96aa3bSJed Brown                               15,     23,     31,
21200a96aa3bSJed Brown                           44, 84, 76, 92, 52, 86, 68, 94, 60, 78, 70, 96,
21210a96aa3bSJed Brown                           45, 85, 77, 93,     54,     72,     62,     74,
21220a96aa3bSJed Brown                               46,     80, 53, 87, 69, 95,         64, 82,
21230a96aa3bSJed Brown                               47,     81,     55,     73,             66,
21240a96aa3bSJed Brown                                   48, 88,         56, 90, 61, 79, 71, 97,
21250a96aa3bSJed Brown                                   49, 89,             58,     63,     75,
21260a96aa3bSJed Brown                                       50,         57, 91,         65, 83,
21270a96aa3bSJed Brown                                       51,             59,             67,
21280a96aa3bSJed Brown                            98, 106, 110, 122, 114, 120, 118, 124,
21290a96aa3bSJed Brown                                 99,      111,      115,      119,
21300a96aa3bSJed Brown                                     100, 107,           116, 121,
21310a96aa3bSJed Brown                                          101,                117,
21320a96aa3bSJed Brown                                               102, 108, 112, 123,
21330a96aa3bSJed Brown                                                    103,      113,
21340a96aa3bSJed Brown                                                         104, 109,
21350a96aa3bSJed Brown                                                              105};
21360a96aa3bSJed Brown     PetscInt ident[125] = {0, 0, 0, 0, 0, 0, 0, 0,
21370a96aa3bSJed 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,
21380a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21390a96aa3bSJed 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,
21400a96aa3bSJed 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,
21410a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0,
21420a96aa3bSJed Brown                            19, 20, 21, 22, 23, 24, 25, 26,
21430a96aa3bSJed Brown                            7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
21440a96aa3bSJed Brown                            1, 2, 3, 4, 5, 6,
21450a96aa3bSJed Brown                            0};
21460a96aa3bSJed Brown 
21470a96aa3bSJed Brown #endif
21480a96aa3bSJed Brown     IS permIS;
21490a96aa3bSJed Brown     DM dmPerm;
21500a96aa3bSJed Brown 
21519566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nPoints,perm,PETSC_USE_POINTER,&permIS));
21529566063dSJacob Faibussowitsch     PetscCall(DMPlexPermute(dmRefined,permIS,&dmPerm));
21530a96aa3bSJed Brown     if (dmPerm) {
21549566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmRefined));
21550a96aa3bSJed Brown       dmRefined = dmPerm;
21560a96aa3bSJed Brown     }
21579566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
21580a96aa3bSJed Brown     {
21590a96aa3bSJed Brown       PetscInt p;
21609566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRoot,"identity"));
21619566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRefined,"identity"));
21620a96aa3bSJed Brown       for (p = 0; p < P4EST_INSUL; p++) {
21639566063dSJacob Faibussowitsch         PetscCall(DMSetLabelValue(dmRoot,"identity",p,p));
21640a96aa3bSJed Brown       }
21650a96aa3bSJed Brown       for (p = 0; p < nPoints; p++) {
21669566063dSJacob Faibussowitsch         PetscCall(DMSetLabelValue(dmRefined,"identity",p,ident[p]));
21670a96aa3bSJed Brown       }
21680a96aa3bSJed Brown     }
21690a96aa3bSJed Brown   }
21709566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(dmRoot,dmRefined,"identity",dm));
21710a96aa3bSJed Brown   mesh                   = (DM_Plex*) (*dm)->data;
21720a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
21739566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
21740a96aa3bSJed Brown   if (rank == 0) {
21759566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRoot,   NULL,"-dm_p4est_ref_root_view"));
21769566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_refined_view"));
21779566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_tree_view"));
21780a96aa3bSJed Brown   }
21799566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRefined));
21809566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRoot));
21810a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(refined));
21820a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(root));
21830a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,(refcube));
21840a96aa3bSJed Brown   PetscFunctionReturn(0);
21850a96aa3bSJed Brown }
21860a96aa3bSJed Brown 
21870a96aa3bSJed Brown static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB)
21880a96aa3bSJed Brown {
21890a96aa3bSJed Brown   void          *ctx;
21900a96aa3bSJed Brown   PetscInt       num;
21910a96aa3bSJed Brown   PetscReal      val;
21920a96aa3bSJed Brown 
21930a96aa3bSJed Brown   PetscFunctionBegin;
21949566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmA,&ctx));
21959566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dmB,ctx));
21969566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmA,dmB));
21979566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dmA,&num,&val));
21989566063dSJacob Faibussowitsch   PetscCall(DMSetOutputSequenceNumber(dmB,num,val));
21990a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
22009566063dSJacob Faibussowitsch     PetscCall(DMClearLocalVectors(dmB));
22019566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->localSection));
22029566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->localSection)));
22030a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
22049566063dSJacob Faibussowitsch     PetscCall(DMClearGlobalVectors(dmB));
22059566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->globalSection));
22069566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->globalSection)));
22070a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
22089566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.section));
22099566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->defaultConstraint.section)));
22103b8ba7d1SJed Brown     dmB->defaultConstraint.section = dmA->defaultConstraint.section;
22119566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.mat));
22129566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(dmB->defaultConstraint.mat)));
22133b8ba7d1SJed Brown     dmB->defaultConstraint.mat = dmA->defaultConstraint.mat;
22149566063dSJacob Faibussowitsch     if (dmA->map) PetscCall(PetscLayoutReference(dmA->map, &dmB->map));
22150a96aa3bSJed Brown   }
22160a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
22179566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->sectionSF));
22189566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&dmB->sectionSF));
22190a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
22200a96aa3bSJed Brown   }
22210a96aa3bSJed Brown   PetscFunctionReturn(0);
22220a96aa3bSJed Brown }
22230a96aa3bSJed Brown 
22240a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
22250a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm,p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF)
22260a96aa3bSJed Brown {
22270a96aa3bSJed Brown   PetscInt       startF, endF, startC, endC, p, nLeaves;
22280a96aa3bSJed Brown   PetscSFNode    *leaves;
22290a96aa3bSJed Brown   PetscSF        sf;
22300a96aa3bSJed Brown   PetscInt       *recv, *send;
22310a96aa3bSJed Brown   PetscMPIInt    tag;
22320a96aa3bSJed Brown   MPI_Request    *recvReqs, *sendReqs;
22330a96aa3bSJed Brown   PetscSection   section;
22340a96aa3bSJed Brown 
22350a96aa3bSJed Brown   PetscFunctionBegin;
22369566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estF,p4estC,&startC,&endC));
22379566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2*(endC-startC),&recv,endC-startC,&recvReqs));
22389566063dSJacob Faibussowitsch   PetscCall(PetscCommGetNewTag(comm,&tag));
22390a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22400a96aa3bSJed Brown     recvReqs[p-startC] = MPI_REQUEST_NULL; /* just in case we don't initiate a receive */
22410a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p+1]) { /* empty coarse partition */
22420a96aa3bSJed Brown       recv[2*(p-startC)]   = 0;
22430a96aa3bSJed Brown       recv[2*(p-startC)+1] = 0;
22440a96aa3bSJed Brown       continue;
22450a96aa3bSJed Brown     }
22460a96aa3bSJed Brown 
22479566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(&recv[2*(p-startC)],2,MPIU_INT,p,tag,comm,&recvReqs[p-startC]));
22480a96aa3bSJed Brown   }
22499566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estC,p4estF,&startF,&endF));
22509566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2*(endF-startF),&send,endF-startF,&sendReqs));
22510a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
22520a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
22530a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
22540a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p+1];
22550a96aa3bSJed Brown     PetscInt         tStart       = (PetscInt) myFineStart->p.which_tree;
22560a96aa3bSJed Brown     PetscInt         tEnd         = (PetscInt) myFineEnd->p.which_tree;
22570a96aa3bSJed Brown     PetscInt         firstCell    = -1, lastCell = -1;
22580a96aa3bSJed Brown     p4est_tree_t     *treeStart   = &(((p4est_tree_t*) p4estC->trees->array)[tStart]);
22590a96aa3bSJed Brown     p4est_tree_t     *treeEnd     = (size_t) tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t*) p4estC->trees->array)[tEnd]) : NULL;
22600a96aa3bSJed Brown     ssize_t          overlapIndex;
22610a96aa3bSJed Brown 
22620a96aa3bSJed Brown     sendReqs[p-startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
22630a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p+1]) continue;
22640a96aa3bSJed Brown 
22650a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
22660a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
22670a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeStart->quadrants),myFineStart,p4est_quadrant_disjoint));
22680a96aa3bSJed Brown       if (overlapIndex < 0) {
22690a96aa3bSJed Brown         firstCell = 0;
22700a96aa3bSJed Brown       } else {
22710a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
22720a96aa3bSJed Brown       }
22730a96aa3bSJed Brown     } else {
22740a96aa3bSJed Brown       firstCell = 0;
22750a96aa3bSJed Brown     }
22760a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
22770a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeEnd->quadrants),myFineEnd,p4est_quadrant_disjoint));
22780a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
22790a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
22800a96aa3bSJed Brown       } else {
22810a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t*) treeEnd->quadrants.array)[overlapIndex]);
22820a96aa3bSJed Brown         p4est_quadrant_t first_desc;
22830a96aa3bSJed Brown         int              equal;
22840a96aa3bSJed Brown 
22850a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_first_descendant,(container,&first_desc,P4EST_QMAXLEVEL));
22860a96aa3bSJed Brown         PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(myFineEnd,&first_desc));
22870a96aa3bSJed Brown         if (equal) {
22880a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
22890a96aa3bSJed Brown         } else {
22900a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
22910a96aa3bSJed Brown         }
22920a96aa3bSJed Brown       }
22930a96aa3bSJed Brown     } else {
22940a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
22950a96aa3bSJed Brown     }
22960a96aa3bSJed Brown     send[2*(p-startF)]   = firstCell;
22970a96aa3bSJed Brown     send[2*(p-startF)+1] = lastCell - firstCell;
22989566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(&send[2*(p-startF)],2,MPIU_INT,p,tag,comm,&sendReqs[p-startF]));
22990a96aa3bSJed Brown   }
23009566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endC-startC),recvReqs,MPI_STATUSES_IGNORE));
23019566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&section));
23029566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section,startC,endC));
23030a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
23040a96aa3bSJed Brown     PetscInt numCells = recv[2*(p-startC)+1];
23059566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section,p,numCells));
23060a96aa3bSJed Brown   }
23079566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
23089566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section,&nLeaves));
23099566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nLeaves,&leaves));
23100a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
23110a96aa3bSJed Brown     PetscInt firstCell = recv[2*(p-startC)];
23120a96aa3bSJed Brown     PetscInt numCells  = recv[2*(p-startC)+1];
23130a96aa3bSJed Brown     PetscInt off, i;
23140a96aa3bSJed Brown 
23159566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section,p,&off));
23160a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
23170a96aa3bSJed Brown       leaves[off+i].rank  = p;
23180a96aa3bSJed Brown       leaves[off+i].index = firstCell + i;
23190a96aa3bSJed Brown     }
23200a96aa3bSJed Brown   }
23219566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm,&sf));
23229566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf,cEnd-cStart,nLeaves,NULL,PETSC_OWN_POINTER,leaves,PETSC_OWN_POINTER));
23239566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
23249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endF-startF),sendReqs,MPI_STATUSES_IGNORE));
23259566063dSJacob Faibussowitsch   PetscCall(PetscFree2(send,sendReqs));
23269566063dSJacob Faibussowitsch   PetscCall(PetscFree2(recv,recvReqs));
23270a96aa3bSJed Brown   *coveringSF = sf;
23280a96aa3bSJed Brown   PetscFunctionReturn(0);
23290a96aa3bSJed Brown }
23300a96aa3bSJed Brown 
23310a96aa3bSJed Brown /* closure points for locally-owned cells */
23320a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints,PetscBool redirect)
23330a96aa3bSJed Brown {
23340a96aa3bSJed Brown   PetscInt          cStart, cEnd;
23350a96aa3bSJed Brown   PetscInt          count, c;
23360a96aa3bSJed Brown   PetscMPIInt       rank;
23370a96aa3bSJed Brown   PetscInt          closureSize = -1;
23380a96aa3bSJed Brown   PetscInt          *closure    = NULL;
23390a96aa3bSJed Brown   PetscSF           pointSF;
23400a96aa3bSJed Brown   PetscInt          nleaves, nroots;
23410a96aa3bSJed Brown   const PetscInt    *ilocal;
23420a96aa3bSJed Brown   const PetscSFNode *iremote;
23430a96aa3bSJed Brown   DM                plex;
23440a96aa3bSJed Brown   DM_Forest         *forest;
23450a96aa3bSJed Brown   DM_Forest_pforest *pforest;
23460a96aa3bSJed Brown 
23470a96aa3bSJed Brown   PetscFunctionBegin;
23480a96aa3bSJed Brown   forest            = (DM_Forest *) dm->data;
23490a96aa3bSJed Brown   pforest           = (DM_Forest_pforest *) forest->data;
23500a96aa3bSJed Brown   cStart            = pforest->cLocalStart;
23510a96aa3bSJed Brown   cEnd              = pforest->cLocalEnd;
23529566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
23539566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm,&pointSF));
23549566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(pointSF,&nroots,&nleaves,&ilocal,&iremote));
23550a96aa3bSJed Brown   nleaves           = PetscMax(0,nleaves);
23560a96aa3bSJed Brown   nroots            = PetscMax(0,nroots);
23570a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
23589566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numClosurePoints,closurePoints));
23599566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
23600a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
23610a96aa3bSJed Brown     PetscInt i;
23629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure));
23630a96aa3bSJed Brown 
23640a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
23650a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
23660a96aa3bSJed Brown       PetscInt loc = -1;
23670a96aa3bSJed Brown 
23689566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(p,nleaves,ilocal,&loc));
23690a96aa3bSJed Brown       if (redirect && loc >= 0) {
23700a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
23710a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
23720a96aa3bSJed Brown       } else {
23730a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
23740a96aa3bSJed Brown         (*closurePoints)[count].index = p;
23750a96aa3bSJed Brown       }
23760a96aa3bSJed Brown     }
23779566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure));
23780a96aa3bSJed Brown   }
23790a96aa3bSJed Brown   PetscFunctionReturn(0);
23800a96aa3bSJed Brown }
23810a96aa3bSJed Brown 
23820a96aa3bSJed Brown static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type)
23830a96aa3bSJed Brown {
23840a96aa3bSJed Brown   PetscMPIInt i;
23850a96aa3bSJed Brown 
23860a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
23870a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode*)a;
23880a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode*)b;
23890a96aa3bSJed Brown 
23900a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
23910a96aa3bSJed Brown   }
23920a96aa3bSJed Brown }
23930a96aa3bSJed Brown 
23940a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
23950a96aa3bSJed Brown {
23960a96aa3bSJed Brown   MPI_Comm          comm;
23970a96aa3bSJed Brown   PetscMPIInt       rank, size;
23980a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
23990a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
24000a96aa3bSJed Brown   PetscInt          numClosureIndices;
24010a96aa3bSJed Brown   PetscInt          numClosurePointsC, numClosurePointsF;
24020a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
24030a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
24040a96aa3bSJed Brown   p4est_quadrant_t  **treeQuads;
24050a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
24060a96aa3bSJed Brown   MPI_Datatype      nodeType;
24070a96aa3bSJed Brown   MPI_Datatype      nodeClosureType;
24080a96aa3bSJed Brown   MPI_Op            sfNodeReduce;
24090a96aa3bSJed Brown   p4est_topidx_t    fltF, lltF, t;
24100a96aa3bSJed Brown   DM                plexC, plexF;
24110a96aa3bSJed Brown   PetscInt          pStartF, pEndF, pStartC, pEndC;
24120a96aa3bSJed Brown   PetscBool         saveInCoarse = PETSC_FALSE;
24130a96aa3bSJed Brown   PetscBool         saveInFine   = PETSC_FALSE;
24140a96aa3bSJed Brown   PetscBool         formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
24150a96aa3bSJed Brown   PetscInt          *cids        = NULL;
24160a96aa3bSJed Brown 
24170a96aa3bSJed Brown   PetscFunctionBegin;
24180a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
24190a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
24200a96aa3bSJed Brown   p4estC   = pforestC->forest;
24210a96aa3bSJed Brown   p4estF   = pforestF->forest;
242208401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo,PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
24230a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
24249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
24259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm,&size));
24269566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine,&plexF));
24279566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF,&pStartF,&pEndF));
24289566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse,&plexC));
24299566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC,&pStartC,&pEndC));
24300a96aa3bSJed Brown   { /* check if the results have been cached */
24310a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
24320a96aa3bSJed Brown 
24339566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(coarse,&adaptCoarse));
24349566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(fine,&adaptFine));
24350a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
24360a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
24379566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestC->pointSelfToAdaptSF)));
24380a96aa3bSJed Brown         *sf  = pforestC->pointSelfToAdaptSF;
24390a96aa3bSJed Brown         if (childIds) {
24409566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
24419566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids,pforestC->pointSelfToAdaptCids,pEndF-pStartF));
24420a96aa3bSJed Brown           *childIds = cids;
24430a96aa3bSJed Brown         }
24440a96aa3bSJed Brown         PetscFunctionReturn(0);
24450a96aa3bSJed Brown       } else {
24460a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
24470a96aa3bSJed Brown         formCids     = PETSC_TRUE;
24480a96aa3bSJed Brown       }
24490a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
24500a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
24519566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestF->pointAdaptToSelfSF)));
24520a96aa3bSJed Brown         *sf  = pforestF->pointAdaptToSelfSF;
24530a96aa3bSJed Brown         if (childIds) {
24549566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
24559566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids,pforestF->pointAdaptToSelfCids,pEndF-pStartF));
24560a96aa3bSJed Brown           *childIds = cids;
24570a96aa3bSJed Brown         }
24580a96aa3bSJed Brown         PetscFunctionReturn(0);
24590a96aa3bSJed Brown       } else {
24600a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
24610a96aa3bSJed Brown         formCids   = PETSC_TRUE;
24620a96aa3bSJed Brown       }
24630a96aa3bSJed Brown     }
24640a96aa3bSJed Brown   }
24650a96aa3bSJed Brown 
24660a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
24670a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
24680a96aa3bSJed Brown   /* create the datatype */
24699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(2,MPIU_INT,&nodeType));
24709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
24719566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_create(DMPforestMaxSFNode,PETSC_FALSE,&sfNodeReduce));
24729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(numClosureIndices*2,MPIU_INT,&nodeClosureType));
24739566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeClosureType));
24740a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
24750a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
24769566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(coarse,numClosureIndices,&numClosurePointsC,&closurePointsC,PETSC_TRUE));
24779566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(fine  ,numClosureIndices,&numClosurePointsF,&closurePointsF,PETSC_FALSE));
24780a96aa3bSJed Brown   /* create pointers for tree lists */
24790a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
24800a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
24819566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(lltF + 1  - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts));
24820a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
24830a96aa3bSJed Brown   if (size > 1) {
24840a96aa3bSJed Brown     PetscInt p;
24850a96aa3bSJed Brown 
24860a96aa3bSJed Brown     for (p = 0; p < size; p++) {
24870a96aa3bSJed Brown       int equal;
24880a96aa3bSJed Brown 
24890a96aa3bSJed Brown       PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal_piggy,(&p4estC->global_first_position[p],&p4estF->global_first_position[p]));
24900a96aa3bSJed Brown       if (!equal) break;
24910a96aa3bSJed Brown     }
24920a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
24930a96aa3bSJed Brown       PetscInt         cStartC, cEndC;
24940a96aa3bSJed Brown       PetscSF          coveringSF;
24950a96aa3bSJed Brown       PetscInt         nleaves;
24960a96aa3bSJed Brown       PetscInt         count;
24970a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
24980a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
24990a96aa3bSJed Brown       p4est_topidx_t   fltC = p4estC->first_local_tree;
25000a96aa3bSJed Brown       p4est_topidx_t   lltC = p4estC->last_local_tree;
25010a96aa3bSJed Brown       p4est_topidx_t   t;
25020a96aa3bSJed Brown       PetscMPIInt      blockSizes[4]   = {P4EST_DIM,2,1,1};
25030a96aa3bSJed Brown       MPI_Aint         blockOffsets[4] = {offsetof(p4est_quadrant_t,x),
25040a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,level),
25050a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,pad16),
25060a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,p)};
25070a96aa3bSJed Brown       MPI_Datatype     blockTypes[4] = {MPI_INT32_T,MPI_INT8_T,MPI_INT16_T,MPI_INT32_T/* p.which_tree */};
25080a96aa3bSJed Brown       MPI_Datatype     quadStruct,quadType;
25090a96aa3bSJed Brown 
25109566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC,0,&cStartC,&cEndC));
25119566063dSJacob Faibussowitsch       PetscCall(DMPforestGetCellCoveringSF(comm,p4estC,p4estF,pforestC->cLocalStart,pforestC->cLocalEnd,&coveringSF));
25129566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coveringSF,NULL,&nleaves,NULL,NULL));
25139566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numClosureIndices*nleaves,&newClosurePointsC));
25149566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&coverQuads));
25159566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cEndC-cStartC,&coverQuadsSend));
25160a96aa3bSJed Brown       count = 0;
25170a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
25180a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
25190a96aa3bSJed Brown         PetscInt     q;
25200a96aa3bSJed Brown 
25219566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&coverQuadsSend[count],tree->quadrants.array,tree->quadrants.elem_count * sizeof(p4est_quadrant_t)));
25220a96aa3bSJed Brown         for (q = 0; (size_t) q < tree->quadrants.elem_count; q++) coverQuadsSend[count+q].p.which_tree = t;
25230a96aa3bSJed Brown         count += tree->quadrants.elem_count;
25240a96aa3bSJed Brown       }
25250a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
25260a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
25270a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
25280a96aa3bSJed Brown        */
25299566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_struct(4,blockSizes,blockOffsets,blockTypes,&quadStruct));
25309566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_resized(quadStruct,0,sizeof(p4est_quadrant_t),&quadType));
25319566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&quadType));
25329566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE));
25339566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE));
25349566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE));
25359566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE));
25369566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadStruct));
25379566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadType));
25389566063dSJacob Faibussowitsch       PetscCall(PetscFree(coverQuadsSend));
25399566063dSJacob Faibussowitsch       PetscCall(PetscFree(closurePointsC));
25409566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coveringSF));
25410a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
25420a96aa3bSJed Brown 
25430a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
25440a96aa3bSJed Brown       {
25450a96aa3bSJed Brown         PetscInt q;
25460a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
25470a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
25480a96aa3bSJed Brown           if (!treeQuadCounts[t-fltF]++) treeQuads[t-fltF] = &coverQuads[q];
25490a96aa3bSJed Brown         }
25500a96aa3bSJed Brown       }
25510a96aa3bSJed Brown     }
25520a96aa3bSJed Brown   }
25530a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
25540a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
25550a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
25560a96aa3bSJed Brown 
25570a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
25580a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t*) tree->quadrants.array;
25590a96aa3bSJed Brown     }
25600a96aa3bSJed Brown   }
25610a96aa3bSJed Brown 
25620a96aa3bSJed Brown   {
25630a96aa3bSJed Brown     PetscInt    p;
25640a96aa3bSJed Brown     PetscInt    cLocalStartF;
25650a96aa3bSJed Brown     PetscSF     pointSF;
25660a96aa3bSJed Brown     PetscSFNode *roots;
25670a96aa3bSJed Brown     PetscInt    *rootType;
25680a96aa3bSJed Brown     DM          refTree = NULL;
25690a96aa3bSJed Brown     DMLabel     canonical;
25700a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
25710a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
25720a96aa3bSJed Brown     PetscInt    coarseOffset;
25730a96aa3bSJed Brown     PetscInt    numCoarseQuads;
25740a96aa3bSJed Brown 
25759566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF-pStartF,&roots));
25769566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF-pStartF,&rootType));
25779566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(fine,&pointSF));
25780a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
25790a96aa3bSJed Brown       roots[p-pStartF].rank  = -1;
25800a96aa3bSJed Brown       roots[p-pStartF].index = -1;
25810a96aa3bSJed Brown       rootType[p-pStartF]    = -1;
25820a96aa3bSJed Brown     }
25830a96aa3bSJed Brown     if (formCids) {
25840a96aa3bSJed Brown       PetscInt child;
25850a96aa3bSJed Brown 
25869566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
25870a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
25889566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF,&refTree));
25899566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure));
25900a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
25919566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]));
25920a96aa3bSJed Brown       }
25939566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(refTree,"canonical",&canonical));
25940a96aa3bSJed Brown     }
25950a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
25960a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
25970a96aa3bSJed Brown       p4est_tree_t     *tree        = &(((p4est_tree_t*) p4estF->trees->array)[t]);
25980a96aa3bSJed Brown       PetscInt         numFineQuads = tree->quadrants.elem_count;
25990a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads = treeQuads[t - fltF];
26000a96aa3bSJed Brown       p4est_quadrant_t *fineQuads   = (p4est_quadrant_t*) tree->quadrants.array;
26010a96aa3bSJed Brown       PetscInt         i, coarseCount = 0;
26020a96aa3bSJed Brown       PetscInt         offset = tree->quadrants_offset;
26030a96aa3bSJed Brown       sc_array_t       coarseQuadsArray;
26040a96aa3bSJed Brown 
26050a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
26060a96aa3bSJed Brown       PetscStackCallP4est(sc_array_init_data,(&coarseQuadsArray,coarseQuads,sizeof(p4est_quadrant_t),(size_t) numCoarseQuads));
26070a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
26080a96aa3bSJed Brown         PetscInt         c     = i + offset;
26090a96aa3bSJed Brown         p4est_quadrant_t *quad = &fineQuads[i];
26100a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
26110a96aa3bSJed Brown         ssize_t          disjoint = -1;
26120a96aa3bSJed Brown 
26130a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
26140a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
26150a96aa3bSJed Brown           PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
26160a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
26170a96aa3bSJed Brown         }
261808401ef6SPierre Jolivet         PetscCheck(disjoint == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"did not find overlapping coarse quad");
26190a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
26200a96aa3bSJed Brown           if (transferIdent) { /* find corners */
26210a96aa3bSJed Brown             PetscInt j = 0;
26220a96aa3bSJed Brown 
26230a96aa3bSJed Brown             do {
26240a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
26250a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
26260a96aa3bSJed Brown                 int              equal;
26270a96aa3bSJed Brown 
26280a96aa3bSJed Brown                 PetscStackCallP4est(p4est_quadrant_corner_descendant,(quad,&cornerQuad,j,quadCoarse->level));
26290a96aa3bSJed Brown                 PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(&cornerQuad,quadCoarse));
26300a96aa3bSJed Brown                 if (equal) {
26310a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
26320a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
26330a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
26340a96aa3bSJed Brown 
26350a96aa3bSJed Brown                   roots[p-pStartF]    = q;
26360a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
26370a96aa3bSJed Brown                   cids[p-pStartF]     = -1;
26380a96aa3bSJed Brown                   j++;
26390a96aa3bSJed Brown                 }
26400a96aa3bSJed Brown               }
26410a96aa3bSJed Brown               coarseCount++;
26420a96aa3bSJed Brown               disjoint = 1;
26430a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
26440a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
26450a96aa3bSJed Brown                 PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
26460a96aa3bSJed Brown               }
26470a96aa3bSJed Brown             } while (!disjoint);
26480a96aa3bSJed Brown           }
26490a96aa3bSJed Brown           continue;
26500a96aa3bSJed Brown         }
26510a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
26520a96aa3bSJed Brown           PetscInt j;
26530a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
26540a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
26550a96aa3bSJed Brown 
26560a96aa3bSJed Brown             roots[p-pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
26570a96aa3bSJed Brown             rootType[p-pStartF] = PETSC_MAX_INT; /* unconditionally accept */
26580a96aa3bSJed Brown             cids[p-pStartF]     = -1;
26590a96aa3bSJed Brown           }
26600a96aa3bSJed Brown         } else {
26610a96aa3bSJed Brown           PetscInt levelDiff = quad->level - quadCoarse->level;
26620a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
26630a96aa3bSJed Brown 
26640a96aa3bSJed Brown           if (formCids) {
26650a96aa3bSJed Brown             PetscInt cl;
26660a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
26670a96aa3bSJed Brown             int      cid;
26680a96aa3bSJed Brown 
266908401ef6SPierre Jolivet             PetscCheck(levelDiff <= 1,PETSC_COMM_SELF,PETSC_ERR_USER,"Recursive child ids not implemented");
26700a96aa3bSJed Brown             PetscStackCallP4estReturn(cid,p4est_quadrant_child_id,(quad));
26719566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure));
26720a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
26730a96aa3bSJed Brown               PetscInt p      = pointClosure[2 * cl];
26740a96aa3bSJed Brown               PetscInt point  = childClosures[cid][2 * cl];
26750a96aa3bSJed Brown               PetscInt ornt   = childClosures[cid][2 * cl + 1];
26760a96aa3bSJed Brown               PetscInt newcid = -1;
26770a96aa3bSJed Brown               DMPolytopeType ct;
26780a96aa3bSJed Brown 
26790a96aa3bSJed Brown               if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
26809566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCellType(refTree, point, &ct));
26810a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
26820a96aa3bSJed Brown               if (!cl) {
26830a96aa3bSJed Brown                 newcid = cid + 1;
26840a96aa3bSJed Brown               } else {
26850a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
26860a96aa3bSJed Brown 
26879566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetTreeParent(refTree,point,&parent,NULL));
26880a96aa3bSJed Brown                 if (parent == point) {
26890a96aa3bSJed Brown                   newcid = -1;
26900a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
26910a96aa3bSJed Brown                   newcid = point;
26920a96aa3bSJed Brown                 } else {
26930a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
26940a96aa3bSJed Brown 
26950a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
26960a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
26979566063dSJacob Faibussowitsch                       PetscCall(DMPlexGetCellType(refTree, parent, &rct));
26980a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
26990a96aa3bSJed Brown                       break;
27000a96aa3bSJed Brown                     }
27010a96aa3bSJed Brown                   }
270208401ef6SPierre Jolivet                   PetscCheck(rcl < P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Couldn't find parent in root closure");
27039566063dSJacob Faibussowitsch                   PetscCall(DMPlexReferenceTreeGetChildSymmetry(refTree,parent,parentOrnt,ornt,point,DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]),NULL,&newcid));
27040a96aa3bSJed Brown                 }
27050a96aa3bSJed Brown               }
27060a96aa3bSJed Brown               if (newcid >= 0) {
27070a96aa3bSJed Brown 
27080a96aa3bSJed Brown                 if (canonical) {
27099566063dSJacob Faibussowitsch                   PetscCall(DMLabelGetValue(canonical,newcid,&newcid));
27100a96aa3bSJed Brown                 }
27110a96aa3bSJed Brown                 proposedCids[cl] = newcid;
27120a96aa3bSJed Brown               }
27130a96aa3bSJed Brown             }
27149566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure));
27150a96aa3bSJed Brown           }
27160a96aa3bSJed Brown           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {{quadCoarse->x,quadCoarse->y,
27170a96aa3bSJed Brown #if defined(P4_TO_P8)
27180a96aa3bSJed Brown                                                        quadCoarse->z
27190a96aa3bSJed Brown #endif
27200a96aa3bSJed Brown                                                       },{0}};
27210a96aa3bSJed Brown           p4est_qcoord_t fineBound[2][P4EST_DIM] = {{quad->x,quad->y,
27220a96aa3bSJed Brown #if defined(P4_TO_P8)
27230a96aa3bSJed Brown                                                      quad->z
27240a96aa3bSJed Brown #endif
27250a96aa3bSJed Brown                                                     },{0}};
27260a96aa3bSJed Brown           PetscInt       j;
27270a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
27280a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
27290a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j]   + P4EST_QUADRANT_LEN(quad->level);
27300a96aa3bSJed Brown           }
27310a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
27320a96aa3bSJed Brown             PetscInt    l, p;
27330a96aa3bSJed Brown             PetscSFNode q;
27340a96aa3bSJed Brown 
27350a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
27360a96aa3bSJed Brown             if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
27370a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
27380a96aa3bSJed Brown               l = 0;
27390a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
27400a96aa3bSJed Brown               PetscInt face = PetscFaceToP4estFace[j - 1];
27410a96aa3bSJed Brown               PetscInt direction = face / 2;
27420a96aa3bSJed Brown               PetscInt coarseFace = -1;
27430a96aa3bSJed Brown 
27440a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
27450a96aa3bSJed Brown                 coarseFace = face;
27460a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27470a96aa3bSJed Brown               } else {
27480a96aa3bSJed Brown                 l = 0;
27490a96aa3bSJed Brown               }
27500a96aa3bSJed Brown #if defined(P4_TO_P8)
27510a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
27520a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
27530a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
27540a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
27550a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
27560a96aa3bSJed Brown               PetscInt  minDir     = PetscMin((direction + 1) % 3,(direction + 2) % 3);
27570a96aa3bSJed Brown               PetscInt  maxDir     = PetscMax((direction + 1) % 3,(direction + 2) % 3);
27580a96aa3bSJed Brown               PetscBool dirTest[2];
27590a96aa3bSJed Brown 
27600a96aa3bSJed Brown               dirTest[0] = (PetscBool) (coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
27610a96aa3bSJed Brown               dirTest[1] = (PetscBool) (coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
27620a96aa3bSJed Brown 
27630a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
27640a96aa3bSJed Brown                 coarseEdge = edge;
27650a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27660a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
27670a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
27680a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27690a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
27700a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
27710a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27720a96aa3bSJed Brown               } else {
27730a96aa3bSJed Brown                 l = 0;
27740a96aa3bSJed Brown               }
27750a96aa3bSJed Brown #endif
27760a96aa3bSJed Brown             } else {
27770a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
27780a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
27790a96aa3bSJed Brown               PetscInt  m;
27800a96aa3bSJed Brown               PetscInt  numMatch     = 0;
27810a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
27820a96aa3bSJed Brown #if defined(P4_TO_P8)
27830a96aa3bSJed Brown               PetscInt coarseEdge = -1;
27840a96aa3bSJed Brown #endif
27850a96aa3bSJed Brown 
27860a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
27870a96aa3bSJed Brown                 dirTest[m] = (PetscBool) (coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
27880a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
27890a96aa3bSJed Brown               }
27900a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
27910a96aa3bSJed Brown                 coarseVertex = vertex;
27920a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
27930a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
27940a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27950a96aa3bSJed Brown                   if (dirTest[m]) {
27960a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
27970a96aa3bSJed Brown                     break;
27980a96aa3bSJed Brown                   }
27990a96aa3bSJed Brown                 }
28000a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
28010a96aa3bSJed Brown #if defined(P4_TO_P8)
28020a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
28030a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
28040a96aa3bSJed Brown                   if (!dirTest[m]) {
28050a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
28060a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
28070a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1,otherDir2);
28080a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1,otherDir2);
28090a96aa3bSJed Brown 
28100a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
28110a96aa3bSJed Brown                     break;
28120a96aa3bSJed Brown                   }
28130a96aa3bSJed Brown                 }
28140a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
28150a96aa3bSJed Brown #endif
28160a96aa3bSJed Brown               } else { /* volume */
28170a96aa3bSJed Brown                 l = 0;
28180a96aa3bSJed Brown               }
28190a96aa3bSJed Brown             }
28200a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
28210a96aa3bSJed Brown             if (l > rootType[p-pStartF]) {
28220a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
28230a96aa3bSJed Brown                 if (transferIdent) {
28240a96aa3bSJed Brown                   roots[p-pStartF] = q;
28250a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
28260a96aa3bSJed Brown                   if (formCids) cids[p-pStartF] = -1;
28270a96aa3bSJed Brown                 }
28280a96aa3bSJed Brown               } else {
28290a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
28300a96aa3bSJed Brown 
28310a96aa3bSJed Brown                 roots[p-pStartF] = q;
28320a96aa3bSJed Brown                 rootType[p-pStartF] = l;
28330a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
28340a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
28350a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
28360a96aa3bSJed Brown                   PetscInt parent;
28370a96aa3bSJed Brown 
28389566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetTreeParent(plexF,thisp,&parent,NULL));
28390a96aa3bSJed Brown                   if (parent == thisp) break;
28400a96aa3bSJed Brown 
28410a96aa3bSJed Brown                   roots[parent-pStartF] = q;
28420a96aa3bSJed Brown                   rootType[parent-pStartF] = PETSC_MAX_INT;
28430a96aa3bSJed Brown                   if (formCids) cids[parent-pStartF] = -1;
28440a96aa3bSJed Brown                   thisp = parent;
28450a96aa3bSJed Brown                 }
28460a96aa3bSJed Brown               }
28470a96aa3bSJed Brown             }
28480a96aa3bSJed Brown           }
28490a96aa3bSJed Brown         }
28500a96aa3bSJed Brown       }
28510a96aa3bSJed Brown     }
28520a96aa3bSJed Brown 
28530a96aa3bSJed 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 */
28540a96aa3bSJed Brown     if (size > 1) {
28550a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
28560a96aa3bSJed Brown 
28579566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&rootTypeCopy));
28589566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(rootTypeCopy,rootType,pEndF-pStartF));
28599566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX));
28609566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX));
28619566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE));
28629566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE));
28630a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28640a96aa3bSJed 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 */
28650a96aa3bSJed Brown           roots[p-pStartF].rank  = -1;
28660a96aa3bSJed Brown           roots[p-pStartF].index = -1;
28670a96aa3bSJed Brown         }
28680a96aa3bSJed Brown         if (formCids && rootTypeCopy[p-pStartF] == PETSC_MAX_INT) {
28690a96aa3bSJed Brown           cids[p-pStartF] = -1; /* we have found an antecedent that is the same: no child id */
28700a96aa3bSJed Brown         }
28710a96aa3bSJed Brown       }
28729566063dSJacob Faibussowitsch       PetscCall(PetscFree(rootTypeCopy));
28739566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,nodeType,roots,roots,sfNodeReduce));
28749566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,nodeType,roots,roots,sfNodeReduce));
28759566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,nodeType,roots,roots,MPI_REPLACE));
28769566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,nodeType,roots,roots,MPI_REPLACE));
28770a96aa3bSJed Brown     }
28789566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootType));
28790a96aa3bSJed Brown 
28800a96aa3bSJed Brown     {
28810a96aa3bSJed Brown       PetscInt    numRoots;
28820a96aa3bSJed Brown       PetscInt    numLeaves;
28830a96aa3bSJed Brown       PetscInt    *leaves;
28840a96aa3bSJed Brown       PetscSFNode *iremote;
28850a96aa3bSJed Brown       /* count leaves */
28860a96aa3bSJed Brown 
28870a96aa3bSJed Brown       numRoots = pEndC - pStartC;
28880a96aa3bSJed Brown 
28890a96aa3bSJed Brown       numLeaves = 0;
28900a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28910a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) numLeaves++;
28920a96aa3bSJed Brown       }
28939566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves,&leaves));
28949566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves,&iremote));
28950a96aa3bSJed Brown       numLeaves = 0;
28960a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28970a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) {
28980a96aa3bSJed Brown           leaves[numLeaves]  = p-pStartF;
28990a96aa3bSJed Brown           iremote[numLeaves] = roots[p-pStartF];
29000a96aa3bSJed Brown           numLeaves++;
29010a96aa3bSJed Brown         }
29020a96aa3bSJed Brown       }
29039566063dSJacob Faibussowitsch       PetscCall(PetscFree(roots));
29049566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm,sf));
29050a96aa3bSJed Brown       if (numLeaves == (pEndF-pStartF)) {
29069566063dSJacob Faibussowitsch         PetscCall(PetscFree(leaves));
29079566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
29080a96aa3bSJed Brown       } else {
29099566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf,numRoots,numLeaves,leaves,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
29100a96aa3bSJed Brown       }
29110a96aa3bSJed Brown     }
29120a96aa3bSJed Brown     if (formCids) {
29130a96aa3bSJed Brown       PetscSF  pointSF;
29140a96aa3bSJed Brown       PetscInt child;
29150a96aa3bSJed Brown 
29169566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF,&refTree));
29179566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(plexF,&pointSF));
29189566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,cids,cids,MPIU_MAX));
29199566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,cids,cids,MPIU_MAX));
29200a96aa3bSJed Brown       if (childIds) *childIds = cids;
29210a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) {
29229566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]));
29230a96aa3bSJed Brown       }
29249566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure));
29250a96aa3bSJed Brown     }
29260a96aa3bSJed Brown   }
29270a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
29289566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
29290a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
29300a96aa3bSJed Brown     if (!childIds) {
29310a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
29320a96aa3bSJed Brown     } else {
29339566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&pforestC->pointSelfToAdaptCids));
29349566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestC->pointSelfToAdaptCids,cids,pEndF-pStartF));
29350a96aa3bSJed Brown     }
29360a96aa3bSJed Brown   } else if (saveInFine) {
29379566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
29380a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
29390a96aa3bSJed Brown     if (!childIds) {
29400a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
29410a96aa3bSJed Brown     } else {
29429566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&pforestF->pointAdaptToSelfCids));
29439566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestF->pointAdaptToSelfCids,cids,pEndF-pStartF));
29440a96aa3bSJed Brown     }
29450a96aa3bSJed Brown   }
29469566063dSJacob Faibussowitsch   PetscCall(PetscFree2(treeQuads,treeQuadCounts));
29479566063dSJacob Faibussowitsch   PetscCall(PetscFree(coverQuads));
29489566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsC));
29499566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsF));
29509566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeClosureType));
29519566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_free(&sfNodeReduce));
29529566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
29530a96aa3bSJed Brown   PetscFunctionReturn(0);
29540a96aa3bSJed Brown }
29550a96aa3bSJed Brown 
29560a96aa3bSJed Brown /* children are sf leaves of parents */
29570a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
29580a96aa3bSJed Brown {
29590a96aa3bSJed Brown   MPI_Comm          comm;
2960d70f29a3SPierre Jolivet   PetscMPIInt       rank;
29610a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
29620a96aa3bSJed Brown   DM                plexC, plexF;
29630a96aa3bSJed Brown   PetscInt          pStartC, pEndC, pStartF, pEndF;
29640a96aa3bSJed Brown   PetscSF           pointTransferSF;
29650a96aa3bSJed Brown   PetscBool         allOnes = PETSC_TRUE;
29660a96aa3bSJed Brown 
29670a96aa3bSJed Brown   PetscFunctionBegin;
29680a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
29690a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
297008401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo,PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
29710a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
29729566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
29730a96aa3bSJed Brown 
29740a96aa3bSJed Brown   {
29750a96aa3bSJed Brown     PetscInt i;
29760a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
29770a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
29780a96aa3bSJed Brown         allOnes = PETSC_FALSE;
29790a96aa3bSJed Brown         break;
29800a96aa3bSJed Brown       }
29810a96aa3bSJed Brown     }
29820a96aa3bSJed Brown   }
29839566063dSJacob Faibussowitsch   PetscCall(DMPforestGetTransferSF_Point(coarse,fine,&pointTransferSF,transferIdent,childIds));
29840a96aa3bSJed Brown   if (allOnes) {
29850a96aa3bSJed Brown     *sf = pointTransferSF;
29860a96aa3bSJed Brown     PetscFunctionReturn(0);
29870a96aa3bSJed Brown   }
29880a96aa3bSJed Brown 
29899566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine,&plexF));
29909566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF,&pStartF,&pEndF));
29919566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse,&plexC));
29929566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC,&pStartC,&pEndC));
29930a96aa3bSJed Brown   {
29940a96aa3bSJed Brown     PetscInt          numRoots;
29950a96aa3bSJed Brown     PetscInt          numLeaves;
29960a96aa3bSJed Brown     const PetscInt    *leaves;
29970a96aa3bSJed Brown     const PetscSFNode *iremote;
29980a96aa3bSJed Brown     PetscInt          d;
29990a96aa3bSJed Brown     PetscSection      leafSection, rootSection;
30000a96aa3bSJed Brown     /* count leaves */
30010a96aa3bSJed Brown 
30029566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointTransferSF,&numRoots,&numLeaves,&leaves,&iremote));
30039566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&rootSection));
30049566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&leafSection));
30059566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(rootSection,pStartC,pEndC));
30069566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(leafSection,pStartF,pEndF));
30070a96aa3bSJed Brown 
30080a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
30090a96aa3bSJed Brown       PetscInt startC, endC, e;
30100a96aa3bSJed Brown 
30119566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC,P4EST_DIM-d,&startC,&endC));
30120a96aa3bSJed Brown       for (e = startC; e < endC; e++) {
30139566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(rootSection,e,dofPerDim[d]));
30140a96aa3bSJed Brown       }
30150a96aa3bSJed Brown     }
30160a96aa3bSJed Brown 
30170a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
30180a96aa3bSJed Brown       PetscInt startF, endF, e;
30190a96aa3bSJed Brown 
30209566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexF,P4EST_DIM-d,&startF,&endF));
30210a96aa3bSJed Brown       for (e = startF; e < endF; e++) {
30229566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafSection,e,dofPerDim[d]));
30230a96aa3bSJed Brown       }
30240a96aa3bSJed Brown     }
30250a96aa3bSJed Brown 
30269566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(rootSection));
30279566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafSection));
30280a96aa3bSJed Brown     {
30290a96aa3bSJed Brown       PetscInt    nroots, nleaves;
30300a96aa3bSJed Brown       PetscInt    *mine, i, p;
30310a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
30320a96aa3bSJed Brown       PetscSFNode *remote;
30330a96aa3bSJed Brown 
30349566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&offsets));
30359566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndC-pStartC,&offsetsRoot));
30360a96aa3bSJed Brown       for (p = pStartC; p < pEndC; p++) {
30379566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootSection,p,&offsetsRoot[p-pStartC]));
30380a96aa3bSJed Brown       }
30399566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE));
30409566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE));
30419566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(rootSection,&nroots));
30420a96aa3bSJed Brown       nleaves = 0;
30430a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
30440a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
30450a96aa3bSJed Brown         PetscInt dof;
30460a96aa3bSJed Brown 
30479566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection,leaf,&dof));
30480a96aa3bSJed Brown         nleaves += dof;
30490a96aa3bSJed Brown       }
30509566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&mine));
30519566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&remote));
30520a96aa3bSJed Brown       nleaves = 0;
30530a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
30540a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
30550a96aa3bSJed Brown         PetscInt dof;
30560a96aa3bSJed Brown         PetscInt off, j;
30570a96aa3bSJed Brown 
30589566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection,leaf,&dof));
30599566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafSection,leaf,&off));
30600a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
30610a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
30620a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
30630a96aa3bSJed Brown           mine[nleaves++]       = off + j;
30640a96aa3bSJed Brown         }
30650a96aa3bSJed Brown       }
30669566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsetsRoot));
30679566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsets));
30689566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm,sf));
30699566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(*sf,nroots,nleaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
30700a96aa3bSJed Brown     }
30719566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
30729566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootSection));
30739566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointTransferSF));
30740a96aa3bSJed Brown   }
30750a96aa3bSJed Brown   PetscFunctionReturn(0);
30760a96aa3bSJed Brown }
30770a96aa3bSJed Brown 
30780a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA)
30790a96aa3bSJed Brown {
30800a96aa3bSJed Brown   DM             adaptA, adaptB;
30810a96aa3bSJed Brown   DMAdaptFlag    purpose;
30820a96aa3bSJed Brown 
30830a96aa3bSJed Brown   PetscFunctionBegin;
30849566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmA,&adaptA));
30859566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmB,&adaptB));
30860a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
30870a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
30889566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmA,&purpose));
30890a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
30909566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30910a96aa3bSJed Brown       PetscFunctionReturn(0);
30920a96aa3bSJed Brown     }
30930a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
30949566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmB,&purpose));
30950a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
30969566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30970a96aa3bSJed Brown       PetscFunctionReturn(0);
30980a96aa3bSJed Brown     }
30990a96aa3bSJed Brown   }
31001baa6e33SBarry Smith   if (sfAtoB) PetscCall(DMPforestGetTransferSF_Internal(dmA,dmB,dofPerDim,sfAtoB,PETSC_TRUE,NULL));
31011baa6e33SBarry Smith   if (sfBtoA) PetscCall(DMPforestGetTransferSF_Internal(dmB,dmA,dofPerDim,sfBtoA,(PetscBool) (sfAtoB == NULL),NULL));
31020a96aa3bSJed Brown   PetscFunctionReturn(0);
31030a96aa3bSJed Brown }
31040a96aa3bSJed Brown 
31050a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex)
31060a96aa3bSJed Brown {
31070a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
31080a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
31090a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
31100a96aa3bSJed Brown   PetscInt          cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
31110a96aa3bSJed Brown   PetscInt          pStart, pEnd, pStartBase, pEndBase, p;
31120a96aa3bSJed Brown   DM                base;
31130a96aa3bSJed Brown   PetscInt          *star     = NULL, starSize;
31140a96aa3bSJed Brown   DMLabelLink       next      = dm->labels;
31150a96aa3bSJed Brown   PetscInt          guess     = 0;
31160a96aa3bSJed Brown   p4est_topidx_t    num_trees = pforest->topo->conn->num_trees;
31170a96aa3bSJed Brown 
31180a96aa3bSJed Brown   PetscFunctionBegin;
31190a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
31200a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
31210a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
31229566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
31230a96aa3bSJed Brown   if (!base) {
31240a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
31250a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
31260a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
31270a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t*) p4est->trees->array;
31280a96aa3bSJed Brown       p4est_topidx_t       t, flt = p4est->first_local_tree;
31290a96aa3bSJed Brown       p4est_topidx_t       llt = pforest->forest->last_local_tree;
31300a96aa3bSJed Brown       DMLabel              ghostLabel;
31310a96aa3bSJed Brown       PetscInt             c;
31320a96aa3bSJed Brown 
31339566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(plex,pforest->ghostName));
31349566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(plex,pforest->ghostName,&ghostLabel));
31350a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
31360a96aa3bSJed Brown         p4est_tree_t     *tree    = &trees[t];
31370a96aa3bSJed Brown         p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
31380a96aa3bSJed Brown         PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
31390a96aa3bSJed Brown         PetscInt         q;
31400a96aa3bSJed Brown 
31410a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
31420a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
31430a96aa3bSJed Brown           PetscInt         f;
31440a96aa3bSJed Brown 
31450a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
31460a96aa3bSJed Brown             p4est_quadrant_t neigh;
31470a96aa3bSJed Brown             int              isOutside;
31480a96aa3bSJed Brown 
31490a96aa3bSJed Brown             PetscStackCallP4est(p4est_quadrant_face_neighbor,(quad,f,&neigh));
31500a96aa3bSJed Brown             PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&neigh));
31510a96aa3bSJed Brown             if (isOutside) {
31520a96aa3bSJed Brown               p4est_topidx_t nt;
31530a96aa3bSJed Brown               PetscInt       nf;
31540a96aa3bSJed Brown 
31550a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
31560a96aa3bSJed Brown               nf = (PetscInt) conn->tree_to_face[t * P4EST_FACES + f];
31570a96aa3bSJed Brown               nf = nf % P4EST_FACES;
31580a96aa3bSJed Brown               if (nt == t && nf == f) {
31590a96aa3bSJed Brown                 PetscInt       plexF = P4estFaceToPetscFace[f];
31600a96aa3bSJed Brown                 const PetscInt *cone;
31610a96aa3bSJed Brown 
31629566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetCone(plex,c,&cone));
31639566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(ghostLabel,cone[plexF],plexF+1));
31640a96aa3bSJed Brown               }
31650a96aa3bSJed Brown             }
31660a96aa3bSJed Brown           }
31670a96aa3bSJed Brown         }
31680a96aa3bSJed Brown       }
31690a96aa3bSJed Brown     }
31700a96aa3bSJed Brown     PetscFunctionReturn(0);
31710a96aa3bSJed Brown   }
31729566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,0,&cStartBase,&cEndBase));
31739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,1,&fStartBase,&fEndBase));
31749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,P4EST_DIM-1,&eStartBase,&eEndBase));
31759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase));
31760a96aa3bSJed Brown 
31779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,0,&cStart,&cEnd));
31789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,1,&fStart,&fEnd));
31799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,P4EST_DIM-1,&eStart,&eEnd));
31809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex,0,&vStart,&vEnd));
31810a96aa3bSJed Brown 
31829566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex,&pStart,&pEnd));
31839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(base,&pStartBase,&pEndBase));
31840a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
31850a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
31860a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
31870a96aa3bSJed Brown   while (next) {
31880a96aa3bSJed Brown     DMLabel   baseLabel;
31890a96aa3bSJed Brown     DMLabel   label = next->label;
31900a96aa3bSJed Brown     PetscBool isDepth, isCellType, isGhost, isVTK, isSpmap;
31910a96aa3bSJed Brown     const char *name;
31920a96aa3bSJed Brown 
31939566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) label, &name));
31949566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"depth",&isDepth));
31950a96aa3bSJed Brown     if (isDepth) {
31960a96aa3bSJed Brown       next = next->next;
31970a96aa3bSJed Brown       continue;
31980a96aa3bSJed Brown     }
31999566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"celltype",&isCellType));
32000a96aa3bSJed Brown     if (isCellType) {
32010a96aa3bSJed Brown       next = next->next;
32020a96aa3bSJed Brown       continue;
32030a96aa3bSJed Brown     }
32049566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"ghost",&isGhost));
32050a96aa3bSJed Brown     if (isGhost) {
32060a96aa3bSJed Brown       next = next->next;
32070a96aa3bSJed Brown       continue;
32080a96aa3bSJed Brown     }
32099566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"vtk",&isVTK));
32100a96aa3bSJed Brown     if (isVTK) {
32110a96aa3bSJed Brown       next = next->next;
32120a96aa3bSJed Brown       continue;
32130a96aa3bSJed Brown     }
32149566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"_forest_base_subpoint_map",&isSpmap));
32150a96aa3bSJed Brown     if (!isSpmap) {
32169566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(base,name,&baseLabel));
32170a96aa3bSJed Brown       if (!baseLabel) {
32180a96aa3bSJed Brown         next = next->next;
32190a96aa3bSJed Brown         continue;
32200a96aa3bSJed Brown       }
32219566063dSJacob Faibussowitsch       PetscCall(DMLabelCreateIndex(baseLabel,pStartBase,pEndBase));
32220a96aa3bSJed Brown     } else baseLabel = NULL;
32230a96aa3bSJed Brown 
32240a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
32250a96aa3bSJed Brown       PetscInt         s, c = -1, l;
32260a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
32270a96aa3bSJed Brown       p4est_quadrant_t * ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
32280a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t*) pforest->forest->trees->array;
32290a96aa3bSJed Brown       p4est_quadrant_t * q;
32300a96aa3bSJed Brown       PetscInt         t, val;
32310a96aa3bSJed Brown       PetscBool        zerosupportpoint = PETSC_FALSE;
32320a96aa3bSJed Brown 
32339566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
32340a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
32350a96aa3bSJed Brown         PetscInt point = star[2*s];
32360a96aa3bSJed Brown 
32370a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
32389566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(plex,point,PETSC_TRUE,&closureSize,&closure));
32390a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
32400a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
32410a96aa3bSJed Brown             do { /* check parents of q */
32420a96aa3bSJed Brown               q = qParent;
32430a96aa3bSJed Brown               if (q == p) {
32440a96aa3bSJed Brown                 c = point;
32450a96aa3bSJed Brown                 break;
32460a96aa3bSJed Brown               }
32479566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex,q,&qParent,NULL));
32480a96aa3bSJed Brown             } while (qParent != q);
32490a96aa3bSJed Brown             if (c != -1) break;
32509566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(plex,pp,&pParent,NULL));
32510a96aa3bSJed Brown             q = closure[2 * l];
32520a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
32530a96aa3bSJed Brown               pp = pParent;
32540a96aa3bSJed Brown               if (pp == q) {
32550a96aa3bSJed Brown                 c = point;
32560a96aa3bSJed Brown                 break;
32570a96aa3bSJed Brown               }
32589566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex,pp,&pParent,NULL));
32590a96aa3bSJed Brown             }
32600a96aa3bSJed Brown             if (c != -1) break;
32610a96aa3bSJed Brown           }
32629566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(plex,point,PETSC_TRUE,NULL,&closure));
32630a96aa3bSJed Brown           if (l < closureSize) break;
32640a96aa3bSJed Brown         } else {
32650a96aa3bSJed Brown           PetscInt supportSize;
32660a96aa3bSJed Brown 
32679566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(plex,point,&supportSize));
32680a96aa3bSJed Brown           zerosupportpoint = (PetscBool) (zerosupportpoint || !supportSize);
32690a96aa3bSJed Brown         }
32700a96aa3bSJed Brown       }
32710a96aa3bSJed Brown       if (c < 0) {
32720a96aa3bSJed Brown         const char* prefix;
32730a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
32740a96aa3bSJed Brown 
32759566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
32769566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_forest_print_label_error",&print,NULL));
32770a96aa3bSJed Brown         if (print) {
32780a96aa3bSJed Brown           PetscInt i;
32790a96aa3bSJed Brown 
328063a3b9bcSJacob Faibussowitsch           PetscCall(PetscPrintf(PETSC_COMM_SELF,"[%d] Failed to find cell with point %" PetscInt_FMT " in its closure for label %s (starSize %" PetscInt_FMT ")\n",PetscGlobalRank,p,baseLabel ? ((PetscObject)baseLabel)->name : "_forest_base_subpoint_map",starSize));
328163a3b9bcSJacob Faibussowitsch           for (i = 0; i < starSize; i++) PetscCall(PetscPrintf(PETSC_COMM_SELF,"  star[%" PetscInt_FMT "] = %" PetscInt_FMT ",%" PetscInt_FMT "\n",i,star[2*i],star[2*i+1]));
32820a96aa3bSJed Brown         }
32839566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star));
32840a96aa3bSJed Brown         if (zerosupportpoint) continue;
328563a3b9bcSJacob Faibussowitsch         else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Failed to find cell with point %" PetscInt_FMT " in its closure for label %s. Rerun with -dm_forest_print_label_error for more information",p,baseLabel ? ((PetscObject) baseLabel)->name : "_forest_base_subpoint_map");
32860a96aa3bSJed Brown       }
32879566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star));
32880a96aa3bSJed Brown 
32890a96aa3bSJed Brown       if (c < cLocalStart) {
32900a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
32910a96aa3bSJed Brown         q = &(ghosts[c]);
32920a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
32930a96aa3bSJed Brown       } else if (c < cLocalEnd) {
32940a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
32950a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
32960a96aa3bSJed Brown 
32970a96aa3bSJed Brown         c -= cLocalStart;
32980a96aa3bSJed Brown 
32990a96aa3bSJed Brown         do {
33000a96aa3bSJed Brown           p4est_tree_t *tree;
33010a96aa3bSJed Brown 
33021dca8a05SBarry Smith           PetscCheck(guess >= lo && guess < num_trees && lo < hi,PETSC_COMM_SELF,PETSC_ERR_PLIB,"failed binary search");
33030a96aa3bSJed Brown           tree = &trees[guess];
33040a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
33050a96aa3bSJed Brown             hi = guess;
33060a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt) tree->quadrants.elem_count) {
33070a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt) tree->quadrants_offset];
33080a96aa3bSJed Brown             t = guess;
33090a96aa3bSJed Brown             break;
33100a96aa3bSJed Brown           } else {
33110a96aa3bSJed Brown             lo = guess + 1;
33120a96aa3bSJed Brown           }
33130a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
33140a96aa3bSJed Brown         } while (1);
33150a96aa3bSJed Brown       } else {
33160a96aa3bSJed Brown         /* get from the end of the ghost layer */
33170a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
33180a96aa3bSJed Brown 
33190a96aa3bSJed Brown         q = &(ghosts[c]);
33200a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
33210a96aa3bSJed Brown       }
33220a96aa3bSJed Brown 
33230a96aa3bSJed Brown       if (l == 0) { /* cell */
33240a96aa3bSJed Brown         if (baseLabel) {
33259566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33260a96aa3bSJed Brown         } else {
33270a96aa3bSJed Brown           val  = t+cStartBase;
33280a96aa3bSJed Brown         }
33299566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label,p,val));
33300a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
33310a96aa3bSJed Brown         p4est_quadrant_t nq;
33320a96aa3bSJed Brown         int              isInside;
33330a96aa3bSJed Brown 
33340a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
33350a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_face_neighbor,(q,l,&nq));
33360a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
33370a96aa3bSJed Brown         if (isInside) {
33380a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
33390a96aa3bSJed Brown           if (baseLabel) {
33409566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33410a96aa3bSJed Brown           } else {
33420a96aa3bSJed Brown             val  = t+cStartBase;
33430a96aa3bSJed Brown           }
33449566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33450a96aa3bSJed Brown         } else {
33460a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
33470a96aa3bSJed Brown 
33480a96aa3bSJed Brown           if (baseLabel) {
33499566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
33500a96aa3bSJed Brown           } else {
33510a96aa3bSJed Brown             val  = f+fStartBase;
33520a96aa3bSJed Brown           }
33539566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33540a96aa3bSJed Brown         }
33550a96aa3bSJed Brown #if defined(P4_TO_P8)
33560a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
33570a96aa3bSJed Brown         p4est_quadrant_t nq;
33580a96aa3bSJed Brown         int              isInside;
33590a96aa3bSJed Brown 
33600a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
33610a96aa3bSJed Brown         PetscStackCallP4est(p8est_quadrant_edge_neighbor,(q,l,&nq));
33620a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
33630a96aa3bSJed Brown         if (isInside) {
33640a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
33650a96aa3bSJed Brown           if (baseLabel) {
33669566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33670a96aa3bSJed Brown           } else {
33680a96aa3bSJed Brown             val  = t+cStartBase;
33690a96aa3bSJed Brown           }
33709566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33710a96aa3bSJed Brown         } else {
33720a96aa3bSJed Brown           int isOutsideFace;
33730a96aa3bSJed Brown 
33740a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutsideFace,p4est_quadrant_is_outside_face,(&nq));
33750a96aa3bSJed Brown           if (isOutsideFace) {
33760a96aa3bSJed Brown             PetscInt f;
33770a96aa3bSJed Brown 
33780a96aa3bSJed Brown             if (nq.x < 0) {
33790a96aa3bSJed Brown               f = 0;
33800a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33810a96aa3bSJed Brown               f = 1;
33820a96aa3bSJed Brown             } else if (nq.y < 0) {
33830a96aa3bSJed Brown               f = 2;
33840a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33850a96aa3bSJed Brown               f = 3;
33860a96aa3bSJed Brown             } else if (nq.z < 0) {
33870a96aa3bSJed Brown               f = 4;
33880a96aa3bSJed Brown             } else {
33890a96aa3bSJed Brown               f = 5;
33900a96aa3bSJed Brown             }
33910a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33920a96aa3bSJed Brown             if (baseLabel) {
33939566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
33940a96aa3bSJed Brown             } else {
33950a96aa3bSJed Brown               val  = f+fStartBase;
33960a96aa3bSJed Brown             }
33979566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
33980a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
33990a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
34000a96aa3bSJed Brown 
34010a96aa3bSJed Brown             if (baseLabel) {
34029566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,e+eStartBase,&val));
34030a96aa3bSJed Brown             } else {
34040a96aa3bSJed Brown               val  = e+eStartBase;
34050a96aa3bSJed Brown             }
34069566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
34070a96aa3bSJed Brown           }
34080a96aa3bSJed Brown         }
34090a96aa3bSJed Brown #endif
34100a96aa3bSJed Brown       } else { /* vertex */
34110a96aa3bSJed Brown         p4est_quadrant_t nq;
34120a96aa3bSJed Brown         int              isInside;
34130a96aa3bSJed Brown 
34140a96aa3bSJed Brown #if defined(P4_TO_P8)
34150a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
34160a96aa3bSJed Brown #else
34170a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
34180a96aa3bSJed Brown #endif
34190a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_corner_neighbor,(q,l,&nq));
34200a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
34210a96aa3bSJed Brown         if (isInside) {
34220a96aa3bSJed Brown           if (baseLabel) {
34239566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
34240a96aa3bSJed Brown           } else {
34250a96aa3bSJed Brown             val  = t+cStartBase;
34260a96aa3bSJed Brown           }
34279566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
34280a96aa3bSJed Brown         } else {
34290a96aa3bSJed Brown           int isOutside;
34300a96aa3bSJed Brown 
34310a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&nq));
34320a96aa3bSJed Brown           if (isOutside) {
34330a96aa3bSJed Brown             PetscInt f = -1;
34340a96aa3bSJed Brown 
34350a96aa3bSJed Brown             if (nq.x < 0) {
34360a96aa3bSJed Brown               f = 0;
34370a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
34380a96aa3bSJed Brown               f = 1;
34390a96aa3bSJed Brown             } else if (nq.y < 0) {
34400a96aa3bSJed Brown               f = 2;
34410a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
34420a96aa3bSJed Brown               f = 3;
34430a96aa3bSJed Brown #if defined(P4_TO_P8)
34440a96aa3bSJed Brown             } else if (nq.z < 0) {
34450a96aa3bSJed Brown               f = 4;
34460a96aa3bSJed Brown             } else {
34470a96aa3bSJed Brown               f = 5;
34480a96aa3bSJed Brown #endif
34490a96aa3bSJed Brown             }
34500a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
34510a96aa3bSJed Brown             if (baseLabel) {
34529566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
34530a96aa3bSJed Brown             } else {
34540a96aa3bSJed Brown               val  = f+fStartBase;
34550a96aa3bSJed Brown             }
34569566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
34570a96aa3bSJed Brown             continue;
34580a96aa3bSJed Brown           }
34590a96aa3bSJed Brown #if defined(P4_TO_P8)
34600a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p8est_quadrant_is_outside_edge,(&nq));
34610a96aa3bSJed Brown           if (isOutside) {
34620a96aa3bSJed Brown             /* outside edge */
34630a96aa3bSJed Brown             PetscInt e = -1;
34640a96aa3bSJed Brown 
34650a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
34660a96aa3bSJed Brown               if (nq.z < 0) {
34670a96aa3bSJed Brown                 if (nq.y < 0) {
34680a96aa3bSJed Brown                   e = 0;
34690a96aa3bSJed Brown                 } else {
34700a96aa3bSJed Brown                   e = 1;
34710a96aa3bSJed Brown                 }
34720a96aa3bSJed Brown               } else {
34730a96aa3bSJed Brown                 if (nq.y < 0) {
34740a96aa3bSJed Brown                   e = 2;
34750a96aa3bSJed Brown                 } else {
34760a96aa3bSJed Brown                   e = 3;
34770a96aa3bSJed Brown                 }
34780a96aa3bSJed Brown               }
34790a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
34800a96aa3bSJed Brown               if (nq.z < 0) {
34810a96aa3bSJed Brown                 if (nq.x < 0) {
34820a96aa3bSJed Brown                   e = 4;
34830a96aa3bSJed Brown                 } else {
34840a96aa3bSJed Brown                   e = 5;
34850a96aa3bSJed Brown                 }
34860a96aa3bSJed Brown               } else {
34870a96aa3bSJed Brown                 if (nq.x < 0) {
34880a96aa3bSJed Brown                   e = 6;
34890a96aa3bSJed Brown                 } else {
34900a96aa3bSJed Brown                   e = 7;
34910a96aa3bSJed Brown                 }
34920a96aa3bSJed Brown               }
34930a96aa3bSJed Brown             } else {
34940a96aa3bSJed Brown               if (nq.y < 0) {
34950a96aa3bSJed Brown                 if (nq.x < 0) {
34960a96aa3bSJed Brown                   e = 8;
34970a96aa3bSJed Brown                 } else {
34980a96aa3bSJed Brown                   e = 9;
34990a96aa3bSJed Brown                 }
35000a96aa3bSJed Brown               } else {
35010a96aa3bSJed Brown                 if (nq.x < 0) {
35020a96aa3bSJed Brown                   e = 10;
35030a96aa3bSJed Brown                 } else {
35040a96aa3bSJed Brown                   e = 11;
35050a96aa3bSJed Brown                 }
35060a96aa3bSJed Brown               }
35070a96aa3bSJed Brown             }
35080a96aa3bSJed Brown 
35090a96aa3bSJed Brown             e    = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
35100a96aa3bSJed Brown             if (baseLabel) {
35119566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,e+eStartBase,&val));
35120a96aa3bSJed Brown             } else {
35130a96aa3bSJed Brown               val  = e+eStartBase;
35140a96aa3bSJed Brown             }
35159566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
35160a96aa3bSJed Brown             continue;
35170a96aa3bSJed Brown           }
35180a96aa3bSJed Brown #endif
35190a96aa3bSJed Brown           {
35200a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
35210a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
35220a96aa3bSJed Brown 
35230a96aa3bSJed Brown             if (baseLabel) {
35249566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,v+vStartBase,&val));
35250a96aa3bSJed Brown             } else {
35260a96aa3bSJed Brown               val  = v+vStartBase;
35270a96aa3bSJed Brown             }
35289566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
35290a96aa3bSJed Brown           }
35300a96aa3bSJed Brown         }
35310a96aa3bSJed Brown       }
35320a96aa3bSJed Brown     }
35330a96aa3bSJed Brown     next = next->next;
35340a96aa3bSJed Brown   }
35350a96aa3bSJed Brown   PetscFunctionReturn(0);
35360a96aa3bSJed Brown }
35370a96aa3bSJed Brown 
35380a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex)
35390a96aa3bSJed Brown {
35400a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
35410a96aa3bSJed Brown   DM                adapt;
35420a96aa3bSJed Brown 
35430a96aa3bSJed Brown   PetscFunctionBegin;
35440a96aa3bSJed Brown   if (pforest->labelsFinalized) PetscFunctionReturn(0);
35450a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
35469566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm,&adapt));
35470a96aa3bSJed Brown   if (!adapt) {
35480a96aa3bSJed Brown     /* Initialize labels from the base dm */
35499566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsInitialize(dm,plex));
35500a96aa3bSJed Brown   } else {
35510a96aa3bSJed Brown     PetscInt    dofPerDim[4]={1, 1, 1, 1};
35520a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
35530a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
35540a96aa3bSJed Brown     PetscInt    *values, *adaptValues;
35550a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
35560a96aa3bSJed Brown     DMLabel     adaptLabel;
35570a96aa3bSJed Brown     DM          adaptPlex;
35580a96aa3bSJed Brown 
35599566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm,&adaptLabel));
35609566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(adapt,&adaptPlex));
35619566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF(adapt,dm,dofPerDim,&transferForward,&transferBackward));
35629566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex,&pStart,&pEnd));
35639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(adaptPlex,&pStartA,&pEndA));
35649566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEnd-pStart,&values,pEndA-pStartA,&adaptValues));
35659566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex,&pointSF));
35660a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
35670a96aa3bSJed Brown       PetscInt p;
35680a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p-pStartA] = -1;
35690a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++)   values[p-pStart]       = -2;
35700a96aa3bSJed Brown       if (transferForward) {
35719566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
35729566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
35730a96aa3bSJed Brown       }
35740a96aa3bSJed Brown       if (transferBackward) {
35759566063dSJacob Faibussowitsch         PetscCall(PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
35769566063dSJacob Faibussowitsch         PetscCall(PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
35770a96aa3bSJed Brown       }
35780a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35790a96aa3bSJed Brown         PetscInt q = p, parent;
35800a96aa3bSJed Brown 
35819566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
35820a96aa3bSJed Brown         while (parent != q) {
35830a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
35840a96aa3bSJed Brown           q    = parent;
35859566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
35860a96aa3bSJed Brown         }
35870a96aa3bSJed Brown       }
35889566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX));
35899566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX));
35909566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE));
35919566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE));
35920a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
359363a3b9bcSJacob Faibussowitsch         PetscCheck(values[p-pStart] != -2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"uncovered point %" PetscInt_FMT,p);
35940a96aa3bSJed Brown       }
35950a96aa3bSJed Brown     }
35960a96aa3bSJed Brown     while (next) {
35970a96aa3bSJed Brown       DMLabel    nextLabel = next->label;
35980a96aa3bSJed Brown       const char *name;
35990a96aa3bSJed Brown       PetscBool  isDepth, isCellType, isGhost, isVTK;
36000a96aa3bSJed Brown       DMLabel    label;
36010a96aa3bSJed Brown       PetscInt   p;
36020a96aa3bSJed Brown 
36039566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject) nextLabel, &name));
36049566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"depth",&isDepth));
36050a96aa3bSJed Brown       if (isDepth) {
36060a96aa3bSJed Brown         next = next->next;
36070a96aa3bSJed Brown         continue;
36080a96aa3bSJed Brown       }
36099566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"celltype",&isCellType));
36100a96aa3bSJed Brown       if (isCellType) {
36110a96aa3bSJed Brown         next = next->next;
36120a96aa3bSJed Brown         continue;
36130a96aa3bSJed Brown       }
36149566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"ghost",&isGhost));
36150a96aa3bSJed Brown       if (isGhost) {
36160a96aa3bSJed Brown         next = next->next;
36170a96aa3bSJed Brown         continue;
36180a96aa3bSJed Brown       }
36199566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"vtk",&isVTK));
36200a96aa3bSJed Brown       if (isVTK) {
36210a96aa3bSJed Brown         next = next->next;
36220a96aa3bSJed Brown         continue;
36230a96aa3bSJed Brown       }
36240a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
36250a96aa3bSJed Brown         next = next->next;
36260a96aa3bSJed Brown         continue;
36270a96aa3bSJed Brown       }
36280a96aa3bSJed Brown       /* label was created earlier */
36299566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm,name,&label));
36300a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) {
36319566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(nextLabel,p,&adaptValues[p]));
36320a96aa3bSJed Brown       }
36330a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
36340a96aa3bSJed Brown 
36351baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
36361baa6e33SBarry Smith       if (transferBackward) PetscCall(PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
36371baa6e33SBarry Smith       if (transferForward) PetscCall(PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
36381baa6e33SBarry Smith       if (transferBackward) PetscCall(PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
36390a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
36400a96aa3bSJed Brown         PetscInt q = p, parent;
36410a96aa3bSJed Brown 
36429566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
36430a96aa3bSJed Brown         while (parent != q) {
36440a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
36450a96aa3bSJed Brown           q    = parent;
36469566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
36470a96aa3bSJed Brown         }
36480a96aa3bSJed Brown       }
36499566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX));
36509566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX));
36519566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE));
36529566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE));
36530a96aa3bSJed Brown 
36540a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
36559566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label,p,values[p]));
36560a96aa3bSJed Brown       }
36570a96aa3bSJed Brown       next = next->next;
36580a96aa3bSJed Brown     }
36599566063dSJacob Faibussowitsch     PetscCall(PetscFree2(values,adaptValues));
36609566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferForward));
36619566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferBackward));
36620a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
36630a96aa3bSJed Brown   }
36640a96aa3bSJed Brown   PetscFunctionReturn(0);
36650a96aa3bSJed Brown }
36660a96aa3bSJed Brown 
36670a96aa3bSJed 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)
36680a96aa3bSJed Brown {
36690a96aa3bSJed Brown   PetscInt       closureSize, c, coordStart, coordEnd, coordDim;
36700a96aa3bSJed Brown   PetscInt       *closure = NULL;
36710a96aa3bSJed Brown   PetscSection   coordSec;
36720a96aa3bSJed Brown 
36730a96aa3bSJed Brown   PetscFunctionBegin;
36749566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex,&coordSec));
36759566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSec,&coordStart,&coordEnd));
36769566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(plex,&coordDim));
36779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure));
36780a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
36790a96aa3bSJed Brown     PetscInt point = closure[2 * c];
36800a96aa3bSJed Brown 
36810a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
36820a96aa3bSJed Brown       PetscInt dof, off;
36830a96aa3bSJed Brown       PetscInt nCoords, i;
36849566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec,point,&dof));
368508401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
36860a96aa3bSJed Brown       nCoords = dof / coordDim;
36879566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec,point,&off));
36880a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
36890a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
36900a96aa3bSJed Brown         double      coordP4est[3]       = {0.};
36910a96aa3bSJed Brown         double      coordP4estMapped[3] = {0.};
36920a96aa3bSJed Brown         PetscInt    j;
36930a96aa3bSJed Brown         PetscReal   treeCoords[P4EST_CHILDREN][3] = {{0.}};
36940a96aa3bSJed Brown         PetscReal   eta[3]                        = {0.};
36950a96aa3bSJed Brown         PetscInt    numRounds                     = 10;
36960a96aa3bSJed Brown         PetscReal   coordGuess[3]                 = {0.};
36970a96aa3bSJed Brown 
36980a96aa3bSJed Brown         eta[0] = (PetscReal) q->x / (PetscReal) P4EST_ROOT_LEN;
36990a96aa3bSJed Brown         eta[1] = (PetscReal) q->y / (PetscReal) P4EST_ROOT_LEN;
37000a96aa3bSJed Brown #if defined(P4_TO_P8)
37010a96aa3bSJed Brown         eta[2] = (PetscReal) q->z / (PetscReal) P4EST_ROOT_LEN;
37020a96aa3bSJed Brown #endif
37030a96aa3bSJed Brown 
37040a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
37050a96aa3bSJed Brown           PetscInt k;
37060a96aa3bSJed Brown 
37070a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
37080a96aa3bSJed Brown         }
37090a96aa3bSJed Brown 
37100a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
37110a96aa3bSJed Brown           PetscInt  k;
37120a96aa3bSJed Brown           PetscReal prod = 1.;
37130a96aa3bSJed Brown 
37140a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
37150a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
37160a96aa3bSJed Brown         }
37170a96aa3bSJed Brown 
37180a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
37190a96aa3bSJed Brown           PetscInt dir;
37200a96aa3bSJed Brown 
37210a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
37220a96aa3bSJed Brown             PetscInt  k;
37230a96aa3bSJed Brown             PetscReal diff[3];
37240a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
37250a96aa3bSJed Brown             PetscReal rhs, scale, update;
37260a96aa3bSJed Brown 
37270a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
37280a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
37290a96aa3bSJed Brown               PetscInt  l;
37300a96aa3bSJed Brown               PetscReal prod = 1.;
37310a96aa3bSJed Brown 
37320a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
37330a96aa3bSJed Brown                 if (l == dir) {
37340a96aa3bSJed Brown                   prod *= (k & (1 << l)) ?  1. : -1.;
37350a96aa3bSJed Brown                 } else {
37360a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
37370a96aa3bSJed Brown                 }
37380a96aa3bSJed Brown               }
37390a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
37400a96aa3bSJed Brown             }
37410a96aa3bSJed Brown             rhs   = 0.;
37420a96aa3bSJed Brown             scale = 0;
37430a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
37440a96aa3bSJed Brown               rhs   += diff[k] * dXdeta[k];
37450a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
37460a96aa3bSJed Brown             }
37470a96aa3bSJed Brown             update    = rhs / scale;
37480a96aa3bSJed Brown             eta[dir] += update;
37490a96aa3bSJed Brown             eta[dir]  = PetscMin(eta[dir],1.);
37500a96aa3bSJed Brown             eta[dir]  = PetscMax(eta[dir],0.);
37510a96aa3bSJed Brown 
37520a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
37530a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
37540a96aa3bSJed Brown               PetscInt  l;
37550a96aa3bSJed Brown               PetscReal prod = 1.;
37560a96aa3bSJed Brown 
37570a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
37580a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
37590a96aa3bSJed Brown             }
37600a96aa3bSJed Brown           }
37610a96aa3bSJed Brown         }
37620a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double) eta[j];
37630a96aa3bSJed Brown 
37640a96aa3bSJed Brown         if (geom) {
37650a96aa3bSJed Brown           (geom->X)(geom,t,coordP4est,coordP4estMapped);
37660a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
37670a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not coded");
37680a96aa3bSJed Brown       }
37690a96aa3bSJed Brown     }
37700a96aa3bSJed Brown   }
37719566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure));
37720a96aa3bSJed Brown   PetscFunctionReturn(0);
37730a96aa3bSJed Brown }
37740a96aa3bSJed Brown 
37750a96aa3bSJed Brown static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex)
37760a96aa3bSJed Brown {
37770a96aa3bSJed Brown   DM_Forest         *forest;
37780a96aa3bSJed Brown   DM_Forest_pforest *pforest;
37790a96aa3bSJed Brown   p4est_geometry_t  *geom;
37800a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd;
37810a96aa3bSJed Brown   Vec               coordLocalVec;
37820a96aa3bSJed Brown   PetscScalar       *coords;
37830a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
37840a96aa3bSJed Brown   p4est_tree_t      *trees;
37850a96aa3bSJed Brown   PetscErrorCode    (*map)(DM,PetscInt, PetscInt, const PetscReal [], PetscReal [], void*);
37860a96aa3bSJed Brown   void              *mapCtx;
37870a96aa3bSJed Brown 
37880a96aa3bSJed Brown   PetscFunctionBegin;
37890a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
37900a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
37910a96aa3bSJed Brown   geom    = pforest->topo->geom;
37929566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx));
37930a96aa3bSJed Brown   if (!geom && !map) PetscFunctionReturn(0);
37949566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex,&coordLocalVec));
37959566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordLocalVec,&coords));
37960a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
37970a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
37980a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
37990a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
38000a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
38010a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
38020a96aa3bSJed Brown     PetscSection coordSec;
38030a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
38040a96aa3bSJed Brown     DM           base;
38050a96aa3bSJed Brown 
38069566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
38079566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
38080a96aa3bSJed Brown     cEnd          = cEndInterior < 0 ? cEnd : cEndInterior;
38099566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm,&base));
38109566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(plex,&coordSec));
38119566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(coordSec,&coordStart,&coordEnd));
38129566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(plex,&coordDim));
38130a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim,3);
38140a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
38150a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
38160a96aa3bSJed Brown       PetscInt dof, off, cell = -1, coarsePoint = -1;
38170a96aa3bSJed Brown       PetscInt nCoords, i;
38189566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec,p,&dof));
381908401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
38200a96aa3bSJed Brown       nCoords = dof / coordDim;
38219566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec,p,&off));
38229566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
38230a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
38240a96aa3bSJed Brown         PetscInt point = star[2 * i];
38250a96aa3bSJed Brown 
38260a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
38270a96aa3bSJed Brown           cell = point;
38280a96aa3bSJed Brown           break;
38290a96aa3bSJed Brown         }
38300a96aa3bSJed Brown       }
38319566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
38320a96aa3bSJed Brown       if (cell >= 0) {
38330a96aa3bSJed Brown         if (cell < cLocalStart) {
38340a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38350a96aa3bSJed Brown 
38360a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
38370a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
38380a96aa3bSJed Brown           cell -= cLocalStart;
38390a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
38400a96aa3bSJed Brown             p4est_tree_t *tree = &(trees[t]);
38410a96aa3bSJed Brown 
38420a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t) cell < tree->quadrants_offset + tree->quadrants.elem_count) {
38430a96aa3bSJed Brown               coarsePoint = t;
38440a96aa3bSJed Brown               break;
38450a96aa3bSJed Brown             }
38460a96aa3bSJed Brown           }
38470a96aa3bSJed Brown         } else {
38480a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38490a96aa3bSJed Brown 
38500a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
38510a96aa3bSJed Brown         }
38520a96aa3bSJed Brown       }
38530a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
38540a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
38550a96aa3bSJed Brown         PetscReal   coordP4est[3]       = {0.};
38560a96aa3bSJed Brown         PetscReal   coordP4estMapped[3] = {0.};
38570a96aa3bSJed Brown         PetscInt    j;
38580a96aa3bSJed Brown 
38590a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
38609566063dSJacob Faibussowitsch         PetscCall((map)(base,coarsePoint,p4estCoordDim,coordP4est,coordP4estMapped,mapCtx));
38610a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
38620a96aa3bSJed Brown       }
38630a96aa3bSJed Brown     }
38640a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
38650a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
38660a96aa3bSJed Brown 
38679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
38689566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
38690a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
38700a96aa3bSJed Brown     if (cLocalStart > 0) {
38710a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38720a96aa3bSJed Brown       PetscInt         count;
38730a96aa3bSJed Brown 
38740a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
38750a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
38760a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
38770a96aa3bSJed Brown 
38789566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count,quad,t,pforest->topo->conn,coords));
38790a96aa3bSJed Brown       }
38800a96aa3bSJed Brown     }
38810a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
38820a96aa3bSJed Brown       p4est_tree_t     *tree    = &(trees[t]);
38830a96aa3bSJed Brown       PetscInt         offset   = cLocalStart + tree->quadrants_offset, i;
38840a96aa3bSJed Brown       PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
38850a96aa3bSJed Brown       p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
38860a96aa3bSJed Brown 
38870a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
38880a96aa3bSJed Brown         PetscInt count = i + offset;
38890a96aa3bSJed Brown 
38909566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count,&quads[i],t,pforest->topo->conn,coords));
38910a96aa3bSJed Brown       }
38920a96aa3bSJed Brown     }
38930a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
38940a96aa3bSJed Brown       p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38950a96aa3bSJed Brown       PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
38960a96aa3bSJed Brown       PetscInt         count;
38970a96aa3bSJed Brown 
38980a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
38990a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
39000a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
39010a96aa3bSJed Brown 
39029566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count + cLocalEnd,quad,t,pforest->topo->conn,coords));
39030a96aa3bSJed Brown       }
39040a96aa3bSJed Brown     }
39050a96aa3bSJed Brown   }
39069566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordLocalVec,&coords));
39070a96aa3bSJed Brown   PetscFunctionReturn(0);
39080a96aa3bSJed Brown }
39090a96aa3bSJed Brown 
3910852b71a7SToby Isaac static PetscErrorCode PforestQuadrantIsInterior (p4est_quadrant_t *quad, PetscBool *is_interior)
3911852b71a7SToby Isaac {
3912852b71a7SToby Isaac   PetscFunctionBegin;
3913852b71a7SToby Isaac   p4est_qcoord_t h = P4EST_QUADRANT_LEN (quad->level);
3914852b71a7SToby Isaac   if ((quad->x > 0) && (quad->x + h < P4EST_ROOT_LEN)
3915852b71a7SToby Isaac #ifdef P4_TO_P8
3916852b71a7SToby Isaac       && (quad->z > 0) && (quad->z + h < P4EST_ROOT_LEN)
3917852b71a7SToby Isaac #endif
3918852b71a7SToby Isaac       && (quad->y > 0) && (quad->y + h < P4EST_ROOT_LEN)) {
3919852b71a7SToby Isaac     *is_interior = PETSC_TRUE;
3920852b71a7SToby Isaac   } else {
3921852b71a7SToby Isaac     *is_interior = PETSC_FALSE;
3922852b71a7SToby Isaac   }
3923852b71a7SToby Isaac   PetscFunctionReturn(0);
3924852b71a7SToby Isaac }
3925852b71a7SToby Isaac 
3926852b71a7SToby Isaac /* We always use DG coordinates with p4est: if they do not match the vertex
3927852b71a7SToby Isaac    coordinates, add space for them in the section */
3928852b71a7SToby Isaac static PetscErrorCode PforestCheckLocalizeCell(DM plex, PetscInt cDim, Vec cVecOld, DM_Forest_pforest *pforest, PetscSection oldSection, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad)
3929852b71a7SToby Isaac {
3930852b71a7SToby Isaac   PetscBool is_interior;
3931852b71a7SToby Isaac 
3932852b71a7SToby Isaac   PetscFunctionBegin;
3933852b71a7SToby Isaac   PetscCall(PforestQuadrantIsInterior(quad, &is_interior));
3934852b71a7SToby Isaac   if (is_interior) { // quads in the interior of a coarse cell can't touch periodic interfaces
3935852b71a7SToby Isaac     PetscCall(PetscSectionSetDof(newSection, cell, 0));
3936852b71a7SToby Isaac     PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3937852b71a7SToby Isaac   } else {
3938852b71a7SToby Isaac     PetscInt     cSize;
3939852b71a7SToby Isaac     PetscScalar *values = NULL;
3940852b71a7SToby Isaac     PetscBool    same_coords = PETSC_TRUE;
3941852b71a7SToby Isaac 
3942852b71a7SToby Isaac     PetscCall(DMPlexVecGetClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3943852b71a7SToby Isaac     PetscAssert(cSize == cDim * P4EST_CHILDREN, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected closure size");
3944852b71a7SToby Isaac     for (int c = 0; c < P4EST_CHILDREN; c++) {
3945852b71a7SToby Isaac       p4est_qcoord_t quad_coords[3];
3946852b71a7SToby Isaac       p4est_qcoord_t h = P4EST_QUADRANT_LEN (quad->level);
3947852b71a7SToby Isaac       double         corner_coords[3];
3948852b71a7SToby Isaac       double         vert_coords[3];
3949852b71a7SToby Isaac       PetscInt corner = PetscVertToP4estVert[c];
3950852b71a7SToby Isaac 
3951852b71a7SToby Isaac       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
3952852b71a7SToby Isaac         vert_coords[d] = PetscRealPart(values[c * cDim + d]);
3953852b71a7SToby Isaac       }
3954852b71a7SToby Isaac 
3955852b71a7SToby Isaac       quad_coords[0] = quad->x;
3956852b71a7SToby Isaac       quad_coords[1] = quad->y;
3957852b71a7SToby Isaac #ifdef P4_TO_P8
3958852b71a7SToby Isaac       quad_coords[2] = quad->z;
3959852b71a7SToby Isaac #endif
3960852b71a7SToby Isaac       for (int d = 0; d < 3; d++) {
3961852b71a7SToby Isaac         quad_coords[d] += (corner & (1 << d)) ? h : 0;
3962852b71a7SToby Isaac       }
3963852b71a7SToby Isaac #ifndef P4_TO_P8
3964852b71a7SToby Isaac       PetscStackCallP4est(p4est_qcoord_to_vertex,(pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3965852b71a7SToby Isaac #else
3966852b71a7SToby Isaac       PetscStackCallP4est(p4est_qcoord_to_vertex,(pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3967852b71a7SToby Isaac #endif
3968852b71a7SToby Isaac       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
3969852b71a7SToby Isaac         if (fabs (vert_coords[d] - corner_coords[d]) > PETSC_SMALL) {
3970852b71a7SToby Isaac           same_coords = PETSC_FALSE;
3971852b71a7SToby Isaac           break;
3972852b71a7SToby Isaac         }
3973852b71a7SToby Isaac       }
3974852b71a7SToby Isaac     }
3975852b71a7SToby Isaac     if (same_coords) {
3976852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, 0));
3977852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3978852b71a7SToby Isaac     } else {
3979852b71a7SToby Isaac       PetscCall(PetscSectionSetDof(newSection, cell, cSize));
3980852b71a7SToby Isaac       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, cSize));
3981852b71a7SToby Isaac     }
3982852b71a7SToby Isaac     PetscCall(DMPlexVecRestoreClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3983852b71a7SToby Isaac   }
3984852b71a7SToby Isaac   PetscFunctionReturn(0);
3985852b71a7SToby Isaac }
3986852b71a7SToby Isaac 
3987852b71a7SToby Isaac static PetscErrorCode PforestLocalizeCell(DM plex, PetscInt cDim, DM_Forest_pforest *pforest, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad, PetscScalar coords[])
3988852b71a7SToby Isaac {
3989852b71a7SToby Isaac   PetscInt  cdof, off;
3990852b71a7SToby Isaac 
3991852b71a7SToby Isaac   PetscFunctionBegin;
3992852b71a7SToby Isaac   PetscCall(PetscSectionGetDof(newSection, cell, &cdof));
3993852b71a7SToby Isaac   if (!cdof) PetscFunctionReturn(0);
3994852b71a7SToby Isaac 
3995852b71a7SToby Isaac   PetscCall(PetscSectionGetOffset(newSection, cell, &off));
3996852b71a7SToby Isaac   for (PetscInt c = 0, pos = off; c < P4EST_CHILDREN; c++) {
3997852b71a7SToby Isaac     p4est_qcoord_t quad_coords[3];
3998852b71a7SToby Isaac     p4est_qcoord_t h = P4EST_QUADRANT_LEN (quad->level);
3999852b71a7SToby Isaac     double         corner_coords[3];
4000852b71a7SToby Isaac     PetscInt corner = PetscVertToP4estVert[c];
4001852b71a7SToby Isaac 
4002852b71a7SToby Isaac     quad_coords[0] = quad->x;
4003852b71a7SToby Isaac     quad_coords[1] = quad->y;
4004852b71a7SToby Isaac #ifdef P4_TO_P8
4005852b71a7SToby Isaac     quad_coords[2] = quad->z;
4006852b71a7SToby Isaac #endif
4007852b71a7SToby Isaac     for (int d = 0; d < 3; d++) {
4008852b71a7SToby Isaac       quad_coords[d] += (corner & (1 << d)) ? h : 0;
4009852b71a7SToby Isaac     }
4010852b71a7SToby Isaac #ifndef P4_TO_P8
4011852b71a7SToby Isaac     PetscStackCallP4est(p4est_qcoord_to_vertex,(pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
4012852b71a7SToby Isaac #else
4013852b71a7SToby Isaac     PetscStackCallP4est(p4est_qcoord_to_vertex,(pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
4014852b71a7SToby Isaac #endif
4015852b71a7SToby Isaac     for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
4016852b71a7SToby Isaac       coords[pos++] = corner_coords[d];
4017852b71a7SToby Isaac     }
4018852b71a7SToby Isaac     for (PetscInt d = PetscMin(cDim, 3); d < cDim; d++) {
4019852b71a7SToby Isaac       coords[pos++] = 0.;
4020852b71a7SToby Isaac     }
4021852b71a7SToby Isaac   }
4022852b71a7SToby Isaac   PetscFunctionReturn(0);
4023852b71a7SToby Isaac }
4024852b71a7SToby Isaac 
40250a96aa3bSJed Brown static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
40260a96aa3bSJed Brown {
40270a96aa3bSJed Brown   DM_Forest         *forest;
40280a96aa3bSJed Brown   DM_Forest_pforest *pforest;
40296858538eSMatthew G. Knepley   DM                base, cdm, cdmCell;
4030852b71a7SToby Isaac   Vec               cVec, cVecOld;
4031852b71a7SToby Isaac   PetscSection      oldSection, newSection;
40320a96aa3bSJed Brown   PetscScalar       *coords2;
40336858538eSMatthew G. Knepley   const PetscReal   *L;
40340a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, coarsePoint;
4035852b71a7SToby Isaac   PetscInt          cDim, newStart, newEnd;
4036852b71a7SToby Isaac   PetscInt          v, vStart, vEnd, cp, cStart, cEnd, cEndInterior;
40370a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
40380a96aa3bSJed Brown   p4est_tree_t      *trees;
40396858538eSMatthew G. Knepley   PetscBool         baseLocalized = PETSC_FALSE;
40400a96aa3bSJed Brown 
40410a96aa3bSJed Brown   PetscFunctionBegin;
40426858538eSMatthew G. Knepley   PetscCall(DMGetPeriodicity(dm,NULL,&L));
40430a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
40449566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cDim));
40459566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
40466858538eSMatthew G. Knepley   if (base) PetscCall(DMGetCoordinatesLocalized(base,&baseLocalized));
40470a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
40486858538eSMatthew G. Knepley   if (!baseLocalized && !L) PetscFunctionReturn(0);
40499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &newStart, &newEnd));
40500a96aa3bSJed Brown 
40519566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &newSection));
40529566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(newSection, 1));
40539566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim));
40549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSection, newStart, newEnd));
40550a96aa3bSJed Brown 
40569566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &oldSection));
40579566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
4058852b71a7SToby Isaac   PetscCall(DMGetCoordinatesLocal(plex, &cVecOld));
40590a96aa3bSJed Brown 
40600a96aa3bSJed Brown   forest      = (DM_Forest*) dm->data;
40610a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
40620a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
40630a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
40640a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
40650a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
40660a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
40670a96aa3bSJed Brown 
40689566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
40699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(plex, &cEndInterior, NULL));
40700a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
4071852b71a7SToby Isaac   cp = 0;
40720a96aa3bSJed Brown   if (cLocalStart > 0) {
40730a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4074852b71a7SToby Isaac     PetscInt         cell;
40750a96aa3bSJed Brown 
4076852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
4077852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
4078852b71a7SToby Isaac 
40790a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
4080852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
40810a96aa3bSJed Brown     }
40820a96aa3bSJed Brown   }
40830a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
40840a96aa3bSJed Brown     p4est_tree_t *tree    = &(trees[t]);
40850a96aa3bSJed Brown     PetscInt     offset   = cLocalStart + tree->quadrants_offset;
40860a96aa3bSJed Brown     PetscInt     numQuads = (PetscInt) tree->quadrants.elem_count;
4087852b71a7SToby Isaac     p4est_quadrant_t *quads = (p4est_quadrant_t *) tree->quadrants.array;
40880a96aa3bSJed Brown     PetscInt     i;
40890a96aa3bSJed Brown 
40900a96aa3bSJed Brown     if (!numQuads) continue;
40910a96aa3bSJed Brown     coarsePoint = t;
4092852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4093852b71a7SToby Isaac       PetscInt cell = i + offset;
4094852b71a7SToby Isaac       p4est_quadrant_t * quad = &quads[i];
40950a96aa3bSJed Brown 
4096852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
40970a96aa3bSJed Brown     }
40980a96aa3bSJed Brown   }
40990a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
41000a96aa3bSJed Brown     p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
41010a96aa3bSJed Brown     PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
41020a96aa3bSJed Brown     PetscInt         count;
41030a96aa3bSJed Brown 
4104852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
41050a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
41060a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
4107852b71a7SToby Isaac       PetscInt cell = count + cLocalEnd;
41080a96aa3bSJed Brown 
4109852b71a7SToby Isaac       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
41100a96aa3bSJed Brown     }
41110a96aa3bSJed Brown   }
4112852b71a7SToby Isaac   PetscAssert(cp == cEnd - cStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT,cp,cEnd-cStart);
41130a96aa3bSJed Brown 
41149566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSection));
41156858538eSMatthew G. Knepley   PetscCall(DMGetCoordinateDM(plex, &cdm));
41166858538eSMatthew G. Knepley   PetscCall(DMClone(cdm, &cdmCell));
41176858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateDM(plex, cdmCell));
41186858538eSMatthew G. Knepley   PetscCall(DMDestroy(&cdmCell));
41196858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinateSection(plex, cDim, newSection));
41209566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &v));
41219566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
41229566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject) cVec, "coordinates"));
41239566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(cVec, cDim));
41249566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE));
41259566063dSJacob Faibussowitsch   PetscCall(VecSetType(cVec, VECSTANDARD));
41269566063dSJacob Faibussowitsch   PetscCall(VecSet(cVec, PETSC_MIN_REAL));
41270a96aa3bSJed Brown 
41280a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
41296858538eSMatthew G. Knepley   PetscCall(VecGetArray(cVec, &coords2));
4130852b71a7SToby Isaac   cp = 0;
4131852b71a7SToby Isaac   if (cLocalStart > 0) {
4132852b71a7SToby Isaac     p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4133852b71a7SToby Isaac     PetscInt         cell;
4134852b71a7SToby Isaac 
4135852b71a7SToby Isaac     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
4136852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[cell];
4137852b71a7SToby Isaac 
4138852b71a7SToby Isaac       coarsePoint = quad->p.which_tree;
4139852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4140852b71a7SToby Isaac     }
4141852b71a7SToby Isaac   }
41420a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
41430a96aa3bSJed Brown     p4est_tree_t *tree    = &(trees[t]);
41440a96aa3bSJed Brown     PetscInt     offset   = cLocalStart + tree->quadrants_offset;
41450a96aa3bSJed Brown     PetscInt     numQuads = (PetscInt) tree->quadrants.elem_count;
4146852b71a7SToby Isaac     p4est_quadrant_t *quads = (p4est_quadrant_t *) tree->quadrants.array;
4147852b71a7SToby Isaac     PetscInt     i;
41480a96aa3bSJed Brown 
41490a96aa3bSJed Brown     if (!numQuads) continue;
4150852b71a7SToby Isaac     coarsePoint = t;
4151852b71a7SToby Isaac     for (i = 0; i < numQuads; i++, cp++) {
4152852b71a7SToby Isaac       PetscInt cell = i + offset;
41530a96aa3bSJed Brown       p4est_quadrant_t * quad = &quads[i];
41540a96aa3bSJed Brown 
4155852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4156852b71a7SToby Isaac     }
4157852b71a7SToby Isaac   }
4158852b71a7SToby Isaac   if (cLocalEnd - cLocalStart < cEnd - cStart) {
4159852b71a7SToby Isaac     p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4160852b71a7SToby Isaac     PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
4161852b71a7SToby Isaac     PetscInt         count;
41620a96aa3bSJed Brown 
4163852b71a7SToby Isaac     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
4164852b71a7SToby Isaac       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
4165852b71a7SToby Isaac       coarsePoint = quad->p.which_tree;
4166852b71a7SToby Isaac       PetscInt cell = count + cLocalEnd;
41670a96aa3bSJed Brown 
4168852b71a7SToby Isaac       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
41690a96aa3bSJed Brown     }
41700a96aa3bSJed Brown   }
41719566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cVec, &coords2));
41726858538eSMatthew G. Knepley   PetscCall(DMSetCellCoordinatesLocal(plex, cVec));
41739566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cVec));
41749566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&newSection));
41750a96aa3bSJed Brown   PetscFunctionReturn(0);
41760a96aa3bSJed Brown }
41770a96aa3bSJed Brown 
41780a96aa3bSJed Brown #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
41790a96aa3bSJed Brown static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
41800a96aa3bSJed Brown {
41810a96aa3bSJed Brown   DM_Forest         *forest;
41820a96aa3bSJed Brown   DM_Forest_pforest *pforest;
41830a96aa3bSJed Brown 
41840a96aa3bSJed Brown   PetscFunctionBegin;
41850a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
41860a96aa3bSJed Brown   pforest = (DM_Forest_pforest *) forest->data;
41879566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointAdaptToSelfSF)));
41889566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointSelfToAdaptSF)));
41899566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
41909566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
41910a96aa3bSJed Brown   PetscFunctionReturn(0);
41920a96aa3bSJed Brown }
41930a96aa3bSJed Brown 
41940a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
41950a96aa3bSJed Brown {
41960a96aa3bSJed Brown   DM_Forest            *forest;
41970a96aa3bSJed Brown   DM_Forest_pforest    *pforest;
41980a96aa3bSJed Brown   DM                   refTree, newPlex, base;
41990a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
42000a96aa3bSJed Brown   MPI_Comm             comm;
42010a96aa3bSJed Brown   PetscBool            isPforest;
42020a96aa3bSJed Brown   PetscInt             dim;
42030a96aa3bSJed Brown   PetscInt             overlap;
42040a96aa3bSJed Brown   p4est_connect_type_t ctype;
42050a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
42060a96aa3bSJed Brown   sc_array_t           *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
42070a96aa3bSJed Brown   PetscSection         parentSection;
42080a96aa3bSJed Brown   PetscSF              pointSF;
42090a96aa3bSJed Brown   size_t               zz, count;
42100a96aa3bSJed Brown   PetscInt             pStart, pEnd;
42110a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
42120a96aa3bSJed Brown 
42130a96aa3bSJed Brown   PetscFunctionBegin;
42140a96aa3bSJed Brown 
42150a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
42160a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
42179566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPFOREST,&isPforest));
421828b400f6SJacob Faibussowitsch   PetscCheck(isPforest,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPFOREST,((PetscObject)dm)->type_name);
42199566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dim));
422063a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim);
42210a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
42220a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
42239566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
42240a96aa3bSJed Brown   if (base) {
42259566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(base,"ghost",&ghostLabelBase));
42260a96aa3bSJed Brown   }
42270a96aa3bSJed Brown   if (!pforest->plex) {
42280a96aa3bSJed Brown     PetscMPIInt size;
42290a96aa3bSJed Brown 
42309566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm,&size));
42319566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm,&newPlex));
42329566063dSJacob Faibussowitsch     PetscCall(DMSetType(newPlex,DMPLEX));
42339566063dSJacob Faibussowitsch     PetscCall(DMSetMatType(newPlex,dm->mattype));
42340a96aa3bSJed Brown     /* share labels */
42359566063dSJacob Faibussowitsch     PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
42369566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyDimension(dm,&adjDim));
42379566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyCodimension(dm,&adjCodim));
42389566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm,&coordDim));
42390a96aa3bSJed Brown     if (adjDim == 0) {
42400a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
42410a96aa3bSJed Brown     } else if (adjCodim == 1) {
42420a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
42430a96aa3bSJed Brown #if defined(P4_TO_P8)
42440a96aa3bSJed Brown     } else if (adjDim == 1) {
42450a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
42460a96aa3bSJed Brown #endif
42470a96aa3bSJed Brown     } else {
424863a3b9bcSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Invalid adjacency dimension %" PetscInt_FMT,adjDim);
42490a96aa3bSJed Brown     }
425063a3b9bcSJacob Faibussowitsch     PetscCheck(ctype == P4EST_CONNECT_FULL,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Adjacency dimension %" PetscInt_FMT " / codimension %" PetscInt_FMT " not supported yet",adjDim,adjCodim);
42519566063dSJacob Faibussowitsch     PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
425260667520SVaclav Hapla     PetscCall(DMPlexSetOverlap_Plex(newPlex,NULL,overlap));
42530a96aa3bSJed Brown 
42540a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
42550a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
42560a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
42570a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
42580a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
42590a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
42600a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
42610a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
42620a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
42630a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
42640a96aa3bSJed Brown 
42650a96aa3bSJed 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));
42660a96aa3bSJed Brown 
42670a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt) first_local_quad;
42680a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt) pforest->forest->local_num_quadrants;
42699566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
42709566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
42719566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
42729566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
42739566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, coordDim));
42749566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(children));
42759566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(parents));
42769566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(childids));
42779566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(leaves));
42789566063dSJacob Faibussowitsch     PetscCall(locidx_pair_to_PetscSFNode(remotes));
42790a96aa3bSJed Brown 
42809566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(newPlex,P4EST_DIM));
42819566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDim(newPlex,coordDim));
42829566063dSJacob Faibussowitsch     PetscCall(DMPlexSetMaxProjectionHeight(newPlex,P4EST_DIM - 1));
42839566063dSJacob Faibussowitsch     PetscCall(DMPlexCreateFromDAG(newPlex,P4EST_DIM,(PetscInt*)points_per_dim->array,(PetscInt*)cone_sizes->array,(PetscInt*)cones->array,(PetscInt*)cone_orientations->array,(PetscScalar*)coords->array));
42849566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(newPlex));
42859566063dSJacob Faibussowitsch     PetscCall(DMCreateReferenceTree_pforest(comm,&refTree));
42869566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(newPlex,refTree));
42879566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(comm,&parentSection));
42889566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(newPlex,&pStart,&pEnd));
42899566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection,pStart,pEnd));
42900a96aa3bSJed Brown     count = children->elem_count;
42910a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
42920a96aa3bSJed Brown       PetscInt child = *((PetscInt*) sc_array_index(children,zz));
42930a96aa3bSJed Brown 
42949566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(parentSection,child,1));
42950a96aa3bSJed Brown     }
42969566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
42979566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(newPlex,parentSection,(PetscInt*)parents->array,(PetscInt*)childids->array));
42989566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&parentSection));
42999566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm,&pointSF));
43000a96aa3bSJed Brown     /*
43010a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
43020a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
43030a96aa3bSJed Brown     */
43049566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(pointSF,pEnd - pStart,(PetscInt)leaves->elem_count,(PetscInt*)leaves->array,PETSC_COPY_VALUES,(PetscSFNode*)remotes->array,PETSC_COPY_VALUES));
43059566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(newPlex,pointSF));
43069566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(dm,pointSF));
43070a96aa3bSJed Brown     {
43080a96aa3bSJed Brown       DM coordDM;
43090a96aa3bSJed Brown 
43109566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43119566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(coordDM,pointSF));
43120a96aa3bSJed Brown     }
43139566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointSF));
43140a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
43150a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
43160a96aa3bSJed Brown     sc_array_destroy (cones);
43170a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
43180a96aa3bSJed Brown     sc_array_destroy (coords);
43190a96aa3bSJed Brown     sc_array_destroy (children);
43200a96aa3bSJed Brown     sc_array_destroy (parents);
43210a96aa3bSJed Brown     sc_array_destroy (childids);
43220a96aa3bSJed Brown     sc_array_destroy (leaves);
43230a96aa3bSJed Brown     sc_array_destroy (remotes);
43240a96aa3bSJed Brown 
43250a96aa3bSJed Brown     {
43260a96aa3bSJed Brown       const PetscReal *maxCell, *L;
43270a96aa3bSJed Brown 
43286858538eSMatthew G. Knepley       PetscCall(DMGetPeriodicity(dm,&maxCell,&L));
43296858538eSMatthew G. Knepley       PetscCall(DMSetPeriodicity(newPlex,maxCell,L));
43309566063dSJacob Faibussowitsch       PetscCall(DMPforestLocalizeCoordinates(dm,newPlex));
43310a96aa3bSJed Brown     }
43320a96aa3bSJed Brown 
43330a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
43340a96aa3bSJed Brown       Vec               coordsGlobal, coordsLocal;
43350a96aa3bSJed Brown       const PetscScalar *globalArray;
43360a96aa3bSJed Brown       PetscScalar       *localArray;
43370a96aa3bSJed Brown       PetscSF           coordSF;
43380a96aa3bSJed Brown       DM                coordDM;
43390a96aa3bSJed Brown 
43409566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43419566063dSJacob Faibussowitsch       PetscCall(DMGetSectionSF(coordDM,&coordSF));
43429566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinates(newPlex, &coordsGlobal));
43439566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal));
43449566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordsGlobal, &globalArray));
43459566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordsLocal, &localArray));
43469566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
43479566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
43489566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordsLocal, &localArray));
43499566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray));
43509566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal));
43510a96aa3bSJed Brown     }
43529566063dSJacob Faibussowitsch     PetscCall(DMPforestMapCoordinates(dm,newPlex));
43530a96aa3bSJed Brown 
43540a96aa3bSJed Brown     pforest->plex = newPlex;
43550a96aa3bSJed Brown 
43560a96aa3bSJed Brown     /* copy labels */
43579566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsFinalize(dm,newPlex));
43580a96aa3bSJed Brown 
43590a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
43600a96aa3bSJed Brown       PetscInt numAdded;
43610a96aa3bSJed Brown       DM       newPlexGhosted;
43620a96aa3bSJed Brown       void     *ctx;
43630a96aa3bSJed Brown 
43649566063dSJacob Faibussowitsch       PetscCall(DMPlexConstructGhostCells(newPlex,pforest->ghostName,&numAdded,&newPlexGhosted));
43659566063dSJacob Faibussowitsch       PetscCall(DMGetApplicationContext(newPlex,&ctx));
43669566063dSJacob Faibussowitsch       PetscCall(DMSetApplicationContext(newPlexGhosted,ctx));
43670a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
43689566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(newPlexGhosted,&pointSF));
43699566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(dm,pointSF));
43709566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&newPlex));
43719566063dSJacob Faibussowitsch       PetscCall(DMPlexSetReferenceTree(newPlexGhosted,refTree));
43729566063dSJacob Faibussowitsch       PetscCall(DMForestClearAdaptivityForest_pforest(dm));
43730a96aa3bSJed Brown       newPlex = newPlexGhosted;
43740a96aa3bSJed Brown 
43750a96aa3bSJed Brown       /* share the labels back */
43769566063dSJacob Faibussowitsch       PetscCall(DMDestroyLabelLinkList_Internal(dm));
43779566063dSJacob Faibussowitsch       PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
43780a96aa3bSJed Brown       pforest->plex = newPlex;
43790a96aa3bSJed Brown     }
43809566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&refTree));
43810a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
43825f80ce2aSJacob Faibussowitsch 
4383d0609cedSBarry Smith       PetscObjectOptionsBegin((PetscObject)newPlex);
43849566063dSJacob Faibussowitsch       PetscCall(DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject,newPlex));
43859566063dSJacob Faibussowitsch       PetscCall(PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)newPlex));
4386d0609cedSBarry Smith       PetscOptionsEnd();
43870a96aa3bSJed Brown     }
43889566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(newPlex,NULL,"-dm_p4est_plex_view"));
43890a96aa3bSJed Brown     {
43906858538eSMatthew G. Knepley       DM           cdm;
43910a96aa3bSJed Brown       PetscSection coordsSec;
43920a96aa3bSJed Brown       Vec          coords;
43930a96aa3bSJed Brown       PetscInt     cDim;
43940a96aa3bSJed Brown 
43959566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(newPlex, &cDim));
43969566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(newPlex, &coordsSec));
43979566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinateSection(dm,cDim, coordsSec));
43989566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coords));
43999566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(dm, coords));
44006858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateDM(newPlex, &cdm));
44016858538eSMatthew G. Knepley       if (cdm) PetscCall(DMSetCellCoordinateDM(dm, cdm));
44026858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinateSection(newPlex, &coordsSec));
44036858538eSMatthew G. Knepley       if (coordsSec) PetscCall(DMSetCellCoordinateSection(dm, cDim, coordsSec));
44046858538eSMatthew G. Knepley       PetscCall(DMGetCellCoordinatesLocal(newPlex, &coords));
44056858538eSMatthew G. Knepley       if (coords) PetscCall(DMSetCellCoordinatesLocal(dm, coords));
44060a96aa3bSJed Brown     }
44070a96aa3bSJed Brown   }
44080a96aa3bSJed Brown   newPlex = pforest->plex;
44090a96aa3bSJed Brown   if (plex) {
44109566063dSJacob Faibussowitsch     PetscCall(DMClone(newPlex,plex));
44116858538eSMatthew G. Knepley #if 0
44129566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
44139566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDM(*plex,coordDM));
44146858538eSMatthew G. Knepley     PetscCall(DMGetCellCoordinateDM(newPlex,&coordDM));
44156858538eSMatthew G. Knepley     PetscCall(DMSetCellCoordinateDM(*plex,coordDM));
44166858538eSMatthew G. Knepley #endif
44179566063dSJacob Faibussowitsch     PetscCall(DMShareDiscretization(dm,*plex));
44180a96aa3bSJed Brown   }
44190a96aa3bSJed Brown   PetscFunctionReturn(0);
44200a96aa3bSJed Brown }
44210a96aa3bSJed Brown 
44220a96aa3bSJed Brown static PetscErrorCode DMSetFromOptions_pforest(PetscOptionItems *PetscOptionsObject,DM dm)
44230a96aa3bSJed Brown {
44240a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44250a96aa3bSJed Brown   char              stringBuffer[256];
44260a96aa3bSJed Brown   PetscBool         flg;
44270a96aa3bSJed Brown 
44280a96aa3bSJed Brown   PetscFunctionBegin;
44299566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions_Forest(PetscOptionsObject,dm));
4430d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"DM" P4EST_STRING " options");
44319566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening","partition forest to allow for coarsening","DMP4estSetPartitionForCoarsening",pforest->partition_for_coarsening,&(pforest->partition_for_coarsening),NULL));
44329566063dSJacob Faibussowitsch   PetscCall(PetscOptionsString("-dm_p4est_ghost_label_name","the name of the ghost label when converting from a DMPlex",NULL,NULL,stringBuffer,sizeof(stringBuffer),&flg));
4433d0609cedSBarry Smith   PetscOptionsHeadEnd();
44340a96aa3bSJed Brown   if (flg) {
44359566063dSJacob Faibussowitsch     PetscCall(PetscFree(pforest->ghostName));
44369566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(stringBuffer,&pforest->ghostName));
44370a96aa3bSJed Brown   }
44380a96aa3bSJed Brown   PetscFunctionReturn(0);
44390a96aa3bSJed Brown }
44400a96aa3bSJed Brown 
44410a96aa3bSJed Brown #if !defined(P4_TO_P8)
44420a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
44430a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
44440a96aa3bSJed Brown #else
44450a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
44460a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
44470a96aa3bSJed Brown #endif
44480a96aa3bSJed Brown 
44490a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
44500a96aa3bSJed Brown {
44510a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44520a96aa3bSJed Brown 
44530a96aa3bSJed Brown   PetscFunctionBegin;
44540a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
44550a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44560a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
44570a96aa3bSJed Brown   PetscFunctionReturn(0);
44580a96aa3bSJed Brown }
44590a96aa3bSJed Brown 
44600a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
44610a96aa3bSJed Brown {
44620a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44630a96aa3bSJed Brown 
44640a96aa3bSJed Brown   PetscFunctionBegin;
44650a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
44660a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44670a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
44680a96aa3bSJed Brown   PetscFunctionReturn(0);
44690a96aa3bSJed Brown }
44700a96aa3bSJed Brown 
44710a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM dm,DM *plex)
44720a96aa3bSJed Brown {
44730a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44740a96aa3bSJed Brown 
44750a96aa3bSJed Brown   PetscFunctionBegin;
44760a96aa3bSJed Brown   if (plex) *plex = NULL;
44779566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
44780a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44790a96aa3bSJed Brown   if (!pforest->plex) {
44809566063dSJacob Faibussowitsch     PetscCall(DMConvert_pforest_plex(dm,DMPLEX,NULL));
44810a96aa3bSJed Brown   }
44829566063dSJacob Faibussowitsch   PetscCall(DMShareDiscretization(dm,pforest->plex));
44830a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
44840a96aa3bSJed Brown   PetscFunctionReturn(0);
44850a96aa3bSJed Brown }
44860a96aa3bSJed Brown 
44870a96aa3bSJed Brown #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
44880a96aa3bSJed Brown static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
44890a96aa3bSJed Brown {
44900a96aa3bSJed Brown   PetscSection   gsc, gsf;
44910a96aa3bSJed Brown   PetscInt       m, n;
44920a96aa3bSJed Brown   DM             cdm;
44930a96aa3bSJed Brown 
44940a96aa3bSJed Brown   PetscFunctionBegin;
44959566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
44969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
44979566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
44989566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
44990a96aa3bSJed Brown 
45009566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), interpolation));
45019566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
45029566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, MATAIJ));
45030a96aa3bSJed Brown 
45049566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
450508401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only interpolation from coarse DM for now");
45060a96aa3bSJed Brown 
45070a96aa3bSJed Brown   {
45080a96aa3bSJed Brown     DM       plexF, plexC;
45090a96aa3bSJed Brown     PetscSF  sf;
45100a96aa3bSJed Brown     PetscInt *cids;
45110a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
45120a96aa3bSJed Brown 
45139566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse,&plexC));
45149566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine,&plexF));
45159566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
45169566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
45179566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
45189566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
45199566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
45200a96aa3bSJed Brown   }
45219566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
45220a96aa3bSJed Brown   /* Use naive scaling */
45239566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
45240a96aa3bSJed Brown   PetscFunctionReturn(0);
45250a96aa3bSJed Brown }
45260a96aa3bSJed Brown 
45270a96aa3bSJed Brown #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
45280a96aa3bSJed Brown static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
45290a96aa3bSJed Brown {
45300a96aa3bSJed Brown   PetscSection   gsc, gsf;
45310a96aa3bSJed Brown   PetscInt       m, n;
45320a96aa3bSJed Brown   DM             cdm;
45330a96aa3bSJed Brown 
45340a96aa3bSJed Brown   PetscFunctionBegin;
45359566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
45369566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n));
45379566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
45389566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m));
45390a96aa3bSJed Brown 
45409566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), injection));
45419566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
45429566063dSJacob Faibussowitsch   PetscCall(MatSetType(*injection, MATAIJ));
45430a96aa3bSJed Brown 
45449566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
454508401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only injection to coarse DM for now");
45460a96aa3bSJed Brown 
45470a96aa3bSJed Brown   {
45480a96aa3bSJed Brown     DM       plexF, plexC;
45490a96aa3bSJed Brown     PetscSF  sf;
45500a96aa3bSJed Brown     PetscInt *cids;
45510a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
45520a96aa3bSJed Brown 
45539566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse,&plexC));
45549566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine,&plexF));
45559566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
45569566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
45579566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
45589566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
45599566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
45600a96aa3bSJed Brown   }
45619566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
45620a96aa3bSJed Brown   /* Use naive scaling */
45630a96aa3bSJed Brown   PetscFunctionReturn(0);
45640a96aa3bSJed Brown }
45650a96aa3bSJed Brown 
45660a96aa3bSJed Brown #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
45670a96aa3bSJed Brown static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
45680a96aa3bSJed Brown {
45690a96aa3bSJed Brown   DM             dmIn, dmVecIn, base, basec, plex, coarseDM;
45700a96aa3bSJed Brown   DM             *hierarchy;
45710a96aa3bSJed Brown   PetscSF        sfRed = NULL;
45720a96aa3bSJed Brown   PetscDS        ds;
45730a96aa3bSJed Brown   Vec            vecInLocal, vecOutLocal;
45740a96aa3bSJed Brown   DMLabel        subpointMap;
45750a96aa3bSJed Brown   PetscInt       minLevel, mh, n_hi, i;
45760a96aa3bSJed Brown   PetscBool      hiforest, *hierarchy_forest;
45770a96aa3bSJed Brown 
45780a96aa3bSJed Brown   PetscFunctionBegin;
45799566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vecIn,&dmVecIn));
45809566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmVecIn,&ds));
458128b400f6SJacob Faibussowitsch   PetscCheck(ds,PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Cannot transfer without a PetscDS object");
45820a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
45830a96aa3bSJed Brown     PetscSection section;
45840a96aa3bSJed Brown     PetscInt     Nf;
45850a96aa3bSJed Brown 
45869566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn,&section));
45879566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section,&Nf));
458863a3b9bcSJacob Faibussowitsch     PetscCheck(Nf <= 3,PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Number of fields %" PetscInt_FMT " are currently not supported! Send an email at petsc-dev@mcs.anl.gov",Nf);
45890a96aa3bSJed Brown   }
45909566063dSJacob Faibussowitsch   PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
459163a3b9bcSJacob Faibussowitsch   PetscCheck(!minLevel,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)",minLevel);
45929566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
459328b400f6SJacob Faibussowitsch   PetscCheck(base,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing base DM");
45940a96aa3bSJed Brown 
45959566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut,0.0));
45960a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
45979566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
45980a96aa3bSJed Brown   } else {
45990a96aa3bSJed Brown     PetscSection secIn, secInRed;
46000a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
46010a96aa3bSJed Brown 
46029566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)base,"_base_migration_sf",(PetscObject*)&sfRed));
460328b400f6SJacob Faibussowitsch     PetscCheck(sfRed,PETSC_COMM_SELF,PETSC_ERR_SUP,"Not the DM set with DMForestSetBaseDM()");
46049566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn),&secInRed));
46059566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF,&vecInRed));
46069566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn,&secIn));
46079566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmVecIn,&vecInLocal));
46089566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
46099566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
46109566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeField(dmVecIn,sfRed,secIn,vecInLocal,secInRed,vecInRed));
46119566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmVecIn,&vecInLocal));
46129566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secInRed));
46130a96aa3bSJed Brown     vecIn = vecInRed;
46140a96aa3bSJed Brown   }
46150a96aa3bSJed Brown 
46160a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
46170a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
46180a96aa3bSJed Brown   hiforest = PETSC_TRUE;
46190a96aa3bSJed Brown 
46200a96aa3bSJed Brown   /* upsweep to the coarsest DM */
46210a96aa3bSJed Brown   n_hi = 0;
46220a96aa3bSJed Brown   coarseDM = dm;
46230a96aa3bSJed Brown   do {
46240a96aa3bSJed Brown     PetscBool isforest;
46250a96aa3bSJed Brown 
46260a96aa3bSJed Brown     dmIn = coarseDM;
46270a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
46289566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dmIn));
46299566063dSJacob Faibussowitsch     PetscCall(DMIsForest(dmIn,&isforest));
463028b400f6SJacob Faibussowitsch     PetscCheck(isforest,PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Cannot currently transfer through a mixed hierarchy! Found DM type %s",((PetscObject)dmIn)->type_name);
46310a96aa3bSJed Brown     coarseDM = NULL;
46320a96aa3bSJed Brown     if (hiforest) {
46339566063dSJacob Faibussowitsch       PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM));
46340a96aa3bSJed Brown     }
46350a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
46360a96aa3bSJed Brown       hiforest = PETSC_FALSE;
46379566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn,&coarseDM));
46380a96aa3bSJed Brown     }
46390a96aa3bSJed Brown     n_hi++;
46400a96aa3bSJed Brown   } while (coarseDM);
46410a96aa3bSJed Brown 
46429566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n_hi,&hierarchy,n_hi,&hierarchy_forest));
46430a96aa3bSJed Brown 
46440a96aa3bSJed Brown   i = 0;
46450a96aa3bSJed Brown   hiforest = PETSC_TRUE;
46460a96aa3bSJed Brown   coarseDM = dm;
46470a96aa3bSJed Brown   do {
46480a96aa3bSJed Brown     dmIn = coarseDM;
46490a96aa3bSJed Brown     coarseDM = NULL;
46500a96aa3bSJed Brown     if (hiforest) {
46519566063dSJacob Faibussowitsch       PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM));
46520a96aa3bSJed Brown     }
46530a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
46540a96aa3bSJed Brown       hiforest = PETSC_FALSE;
46559566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn,&coarseDM));
46560a96aa3bSJed Brown     }
46570a96aa3bSJed Brown     i++;
46580a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
46590a96aa3bSJed Brown   } while (coarseDM);
46600a96aa3bSJed Brown 
46610a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
46629566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn,&plex));
46630a96aa3bSJed Brown 
46640a96aa3bSJed Brown   /* Check this plex is compatible with the base */
46650a96aa3bSJed Brown   {
46660a96aa3bSJed Brown     IS       gnum[2];
46670a96aa3bSJed Brown     PetscInt ncells[2],gncells[2];
46680a96aa3bSJed Brown 
46699566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(base,&gnum[0]));
46709566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(plex,&gnum[1]));
46719566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[0],NULL,&ncells[0]));
46729566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[1],NULL,&ncells[1]));
46731c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(ncells,gncells,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
467463a3b9bcSJacob Faibussowitsch     PetscCheck(gncells[0] == gncells[1],PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Invalid number of base cells! Expected %" PetscInt_FMT ", found %" PetscInt_FMT,gncells[0]+1,gncells[1]+1);
46750a96aa3bSJed Brown   }
46760a96aa3bSJed Brown 
46779566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dmIn,"_forest_base_subpoint_map",&subpointMap));
467828b400f6SJacob Faibussowitsch   PetscCheck(subpointMap,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing _forest_base_subpoint_map label");
46790a96aa3bSJed Brown 
46809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(base,&mh));
46819566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(plex,mh));
46820a96aa3bSJed Brown 
46839566063dSJacob Faibussowitsch   PetscCall(DMClone(base,&basec));
46849566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmVecIn,basec));
46850a96aa3bSJed Brown   if (sfRed) {
46869566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
46870a96aa3bSJed Brown     vecInLocal = vecIn;
46880a96aa3bSJed Brown   } else {
46899566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(basec,&vecInLocal));
46909566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(basec,vecIn,INSERT_VALUES,vecInLocal));
46919566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(basec,vecIn,INSERT_VALUES,vecInLocal));
46920a96aa3bSJed Brown   }
46930a96aa3bSJed Brown 
46949566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmIn,&vecOutLocal));
46950a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
46960a96aa3bSJed Brown     PetscSF            basetocoarse;
46970a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
46980a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
46990a96aa3bSJed Brown     PetscMPIInt        rank;
47000a96aa3bSJed Brown     PetscSFNode       *remotes;
47010a96aa3bSJed Brown     PetscSection       secIn, secOut;
47020a96aa3bSJed Brown     PetscInt          *remoteOffsets;
47030a96aa3bSJed Brown     PetscSF            transferSF;
47040a96aa3bSJed Brown     const PetscScalar *inArray;
47050a96aa3bSJed Brown     PetscScalar       *outArray;
47060a96aa3bSJed Brown 
47079566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
47089566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(basec, &bStart, &bEnd));
47090a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
47109566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &iStart, &iEnd));
47110a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
47120a96aa3bSJed Brown 
47139566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &remotes));
47140a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
47150a96aa3bSJed Brown       PetscInt index;
47160a96aa3bSJed Brown 
47170a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
47189566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(subpointMap, leaf, &index));
47190a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
47200a96aa3bSJed Brown     }
47210a96aa3bSJed Brown 
47229566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
47239566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
47249566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(basetocoarse));
47259566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(basec,&secIn));
47269566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn),&secOut));
47279566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
47289566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
47299566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
47309566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(vecOutLocal, &outArray));
47319566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecInLocal, &inArray));
47329566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
47339566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
47349566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecInLocal, &inArray));
47359566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray));
47369566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferSF));
47379566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secOut));
47389566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&basetocoarse));
47390a96aa3bSJed Brown   }
47409566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecInLocal));
47419566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&basec));
47429566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecIn));
47430a96aa3bSJed Brown 
47440a96aa3bSJed Brown   /* output */
47450a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
47460a96aa3bSJed Brown     Vec vecOut1, vecOut2;
47470a96aa3bSJed Brown     DM  fineDM;
47480a96aa3bSJed Brown 
47499566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmIn,&vecOut1));
47509566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut1));
47519566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal));
47520a96aa3bSJed Brown     for (i = 1; i < n_hi-1; i++) {
47530a96aa3bSJed Brown       fineDM  = hierarchy[i];
47549566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(fineDM,&vecOut2));
47559566063dSJacob Faibussowitsch       PetscCall(DMForestTransferVec(dmIn,vecOut1,fineDM,vecOut2,PETSC_TRUE,0.0));
47569566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1));
47570a96aa3bSJed Brown       vecOut1 = vecOut2;
47580a96aa3bSJed Brown       dmIn    = fineDM;
47590a96aa3bSJed Brown     }
47609566063dSJacob Faibussowitsch     PetscCall(DMForestTransferVec(dmIn,vecOut1,dm,vecOut,PETSC_TRUE,0.0));
47619566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1));
47620a96aa3bSJed Brown   } else {
47639566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut));
47649566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal));
47650a96aa3bSJed Brown   }
47669566063dSJacob Faibussowitsch   PetscCall(PetscFree2(hierarchy,hierarchy_forest));
47670a96aa3bSJed Brown   PetscFunctionReturn(0);
47680a96aa3bSJed Brown }
47690a96aa3bSJed Brown 
47700a96aa3bSJed Brown #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
47710a96aa3bSJed Brown static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
47720a96aa3bSJed Brown {
47730a96aa3bSJed Brown   DM             adaptIn, adaptOut, plexIn, plexOut;
47740a96aa3bSJed Brown   DM_Forest      *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
47750a96aa3bSJed Brown   PetscInt       dofPerDim[] = {1, 1, 1, 1};
47760a96aa3bSJed Brown   PetscSF        inSF = NULL, outSF = NULL;
47770a96aa3bSJed Brown   PetscInt       *inCids = NULL, *outCids = NULL;
47780a96aa3bSJed Brown   DMAdaptFlag    purposeIn, purposeOut;
47790a96aa3bSJed Brown 
47800a96aa3bSJed Brown   PetscFunctionBegin;
47810a96aa3bSJed Brown   forestOut = (DM_Forest *) dmOut->data;
47820a96aa3bSJed Brown   forestIn  = (DM_Forest *) dmIn->data;
47830a96aa3bSJed Brown 
47849566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmOut,&adaptOut));
47859566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmOut,&purposeOut));
47860a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *) adaptOut->data : NULL;
47870a96aa3bSJed Brown 
47889566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmIn,&adaptIn));
47899566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmIn,&purposeIn));
47900a96aa3bSJed Brown   forestAdaptIn  = adaptIn ? (DM_Forest *) adaptIn->data : NULL;
47910a96aa3bSJed Brown 
47920a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
47930a96aa3bSJed Brown     switch (purposeOut) {
47940a96aa3bSJed Brown     case DM_ADAPT_REFINE:
47959566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
47969566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
47970a96aa3bSJed Brown       break;
47980a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
47990a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
48009566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&outCids));
48019566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48020a96aa3bSJed Brown       break;
48030a96aa3bSJed Brown     default:
48049566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48059566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
48069566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48079566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48080a96aa3bSJed Brown     }
48090a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
48100a96aa3bSJed Brown     switch (purposeIn) {
48110a96aa3bSJed Brown     case DM_ADAPT_REFINE:
48129566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&inCids));
48139566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48140a96aa3bSJed Brown       break;
48150a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
48160a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
48179566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48189566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48190a96aa3bSJed Brown       break;
48200a96aa3bSJed Brown     default:
48219566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48229566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
48239566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48249566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48250a96aa3bSJed Brown     }
48260a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Only support transfer from pre-adaptivity to post-adaptivity right now");
48279566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn,&plexIn));
48289566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmOut,&plexOut));
48290a96aa3bSJed Brown 
48309566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferVecTree(plexIn,vecIn,plexOut,vecOut,inSF,outSF,inCids,outCids,useBCs,time));
48319566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
48329566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
48339566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&inSF));
48349566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&outSF));
48359566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
48369566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
48370a96aa3bSJed Brown   PetscFunctionReturn(0);
48380a96aa3bSJed Brown }
48390a96aa3bSJed Brown 
48400a96aa3bSJed Brown #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
48410a96aa3bSJed Brown static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm,DM *cdm)
48420a96aa3bSJed Brown {
48430a96aa3bSJed Brown   DM             plex;
48440a96aa3bSJed Brown 
48450a96aa3bSJed Brown   PetscFunctionBegin;
48460a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
48479566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48489566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(plex,cdm));
48499566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)*cdm));
48500a96aa3bSJed Brown   PetscFunctionReturn(0);
48510a96aa3bSJed Brown }
48520a96aa3bSJed Brown 
48530a96aa3bSJed Brown #define VecViewLocal_pforest _append_pforest(VecViewLocal)
48540a96aa3bSJed Brown static PetscErrorCode VecViewLocal_pforest(Vec vec,PetscViewer viewer)
48550a96aa3bSJed Brown {
48560a96aa3bSJed Brown   DM             dm, plex;
48570a96aa3bSJed Brown 
48580a96aa3bSJed Brown   PetscFunctionBegin;
48599566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48609566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48619566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48629566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Local(vec,viewer));
48639566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48640a96aa3bSJed Brown   PetscFunctionReturn(0);
48650a96aa3bSJed Brown }
48660a96aa3bSJed Brown 
48670a96aa3bSJed Brown #define VecView_pforest _append_pforest(VecView)
48680a96aa3bSJed Brown static PetscErrorCode VecView_pforest(Vec vec,PetscViewer viewer)
48690a96aa3bSJed Brown {
48700a96aa3bSJed Brown   DM             dm, plex;
48710a96aa3bSJed Brown 
48720a96aa3bSJed Brown   PetscFunctionBegin;
48739566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48749566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48759566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48769566063dSJacob Faibussowitsch   PetscCall(VecView_Plex(vec,viewer));
48779566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48780a96aa3bSJed Brown   PetscFunctionReturn(0);
48790a96aa3bSJed Brown }
48800a96aa3bSJed Brown 
48810a96aa3bSJed Brown #define VecView_pforest_Native _infix_pforest(VecView,_Native)
48820a96aa3bSJed Brown static PetscErrorCode VecView_pforest_Native(Vec vec,PetscViewer viewer)
48830a96aa3bSJed Brown {
48840a96aa3bSJed Brown   DM             dm, plex;
48850a96aa3bSJed Brown 
48860a96aa3bSJed Brown   PetscFunctionBegin;
48879566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48889566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48899566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48909566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Native(vec,viewer));
48919566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48920a96aa3bSJed Brown   PetscFunctionReturn(0);
48930a96aa3bSJed Brown }
48940a96aa3bSJed Brown 
48950a96aa3bSJed Brown #define VecLoad_pforest _append_pforest(VecLoad)
48960a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest(Vec vec,PetscViewer viewer)
48970a96aa3bSJed Brown {
48980a96aa3bSJed Brown   DM             dm, plex;
48990a96aa3bSJed Brown 
49000a96aa3bSJed Brown   PetscFunctionBegin;
49019566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
49029566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49039566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
49049566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex(vec,viewer));
49059566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
49060a96aa3bSJed Brown   PetscFunctionReturn(0);
49070a96aa3bSJed Brown }
49080a96aa3bSJed Brown 
49090a96aa3bSJed Brown #define VecLoad_pforest_Native _infix_pforest(VecLoad,_Native)
49100a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest_Native(Vec vec,PetscViewer viewer)
49110a96aa3bSJed Brown {
49120a96aa3bSJed Brown   DM             dm, plex;
49130a96aa3bSJed Brown 
49140a96aa3bSJed Brown   PetscFunctionBegin;
49159566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
49169566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49179566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
49189566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex_Native(vec,viewer));
49199566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
49200a96aa3bSJed Brown   PetscFunctionReturn(0);
49210a96aa3bSJed Brown }
49220a96aa3bSJed Brown 
49230a96aa3bSJed Brown #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
49240a96aa3bSJed Brown static PetscErrorCode DMCreateGlobalVector_pforest(DM dm,Vec *vec)
49250a96aa3bSJed Brown {
49260a96aa3bSJed Brown   PetscFunctionBegin;
49279566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector_Section_Private(dm,vec));
49289566063dSJacob Faibussowitsch   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
49299566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
49309566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
49319566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
49329566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
49330a96aa3bSJed Brown   PetscFunctionReturn(0);
49340a96aa3bSJed Brown }
49350a96aa3bSJed Brown 
49360a96aa3bSJed Brown #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
49370a96aa3bSJed Brown static PetscErrorCode DMCreateLocalVector_pforest(DM dm,Vec *vec)
49380a96aa3bSJed Brown {
49390a96aa3bSJed Brown   PetscFunctionBegin;
49409566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector_Section_Private(dm,vec));
49419566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
49420a96aa3bSJed Brown   PetscFunctionReturn(0);
49430a96aa3bSJed Brown }
49440a96aa3bSJed Brown 
49450a96aa3bSJed Brown #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
49460a96aa3bSJed Brown static PetscErrorCode DMCreateMatrix_pforest(DM dm,Mat *mat)
49470a96aa3bSJed Brown {
49480a96aa3bSJed Brown   DM             plex;
49490a96aa3bSJed Brown 
49500a96aa3bSJed Brown   PetscFunctionBegin;
49510a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49529566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49530a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only;  /* maybe this should go into forest->plex */
49549566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(plex,mat));
49559566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*mat,dm));
49560a96aa3bSJed Brown   PetscFunctionReturn(0);
49570a96aa3bSJed Brown }
49580a96aa3bSJed Brown 
49590a96aa3bSJed Brown #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
49600a96aa3bSJed Brown static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, InsertMode mode, Vec localX)
49610a96aa3bSJed Brown {
49620a96aa3bSJed Brown   DM             plex;
49630a96aa3bSJed Brown 
49640a96aa3bSJed Brown   PetscFunctionBegin;
49650a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49669566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49679566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(plex,time,funcs,ctxs,mode,localX));
49680a96aa3bSJed Brown   PetscFunctionReturn(0);
49690a96aa3bSJed Brown }
49700a96aa3bSJed Brown 
49710a96aa3bSJed Brown #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
49720a96aa3bSJed 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)
49730a96aa3bSJed Brown {
49740a96aa3bSJed Brown   DM             plex;
49750a96aa3bSJed Brown 
49760a96aa3bSJed Brown   PetscFunctionBegin;
49770a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49789566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49799566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(plex,time,label,numIds,ids,Ncc,comps,funcs,ctxs,mode,localX));
49800a96aa3bSJed Brown   PetscFunctionReturn(0);
49810a96aa3bSJed Brown }
49820a96aa3bSJed Brown 
49830a96aa3bSJed Brown #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
49840a96aa3bSJed Brown PetscErrorCode DMProjectFieldLocal_pforest(DM dm, PetscReal time, Vec localU,void (**funcs) (PetscInt, PetscInt, PetscInt,
49850a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
49860a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
49870a96aa3bSJed Brown                                                                              PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),InsertMode mode, Vec localX)
49880a96aa3bSJed Brown {
49890a96aa3bSJed Brown   DM             plex;
49900a96aa3bSJed Brown 
49910a96aa3bSJed Brown   PetscFunctionBegin;
49920a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49939566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49949566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(plex,time,localU,funcs,mode,localX));
49950a96aa3bSJed Brown   PetscFunctionReturn(0);
49960a96aa3bSJed Brown }
49970a96aa3bSJed Brown 
49980a96aa3bSJed Brown #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
49990a96aa3bSJed Brown PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal *diff)
50000a96aa3bSJed Brown {
50010a96aa3bSJed Brown   DM             plex;
50020a96aa3bSJed Brown 
50030a96aa3bSJed Brown   PetscFunctionBegin;
50040a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50059566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50069566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(plex,time,funcs,ctxs,X,diff));
50070a96aa3bSJed Brown   PetscFunctionReturn(0);
50080a96aa3bSJed Brown }
50090a96aa3bSJed Brown 
50100a96aa3bSJed Brown #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
50110a96aa3bSJed Brown PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal diff[])
50120a96aa3bSJed Brown {
50130a96aa3bSJed Brown   DM             plex;
50140a96aa3bSJed Brown 
50150a96aa3bSJed Brown   PetscFunctionBegin;
50160a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50179566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50189566063dSJacob Faibussowitsch   PetscCall(DMComputeL2FieldDiff(plex,time,funcs,ctxs,X,diff));
50190a96aa3bSJed Brown   PetscFunctionReturn(0);
50200a96aa3bSJed Brown }
50210a96aa3bSJed Brown 
50220a96aa3bSJed Brown #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
50230a96aa3bSJed Brown static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
50240a96aa3bSJed Brown {
50250a96aa3bSJed Brown   DM             plex;
50260a96aa3bSJed Brown   PetscSection   section;
50270a96aa3bSJed Brown 
50280a96aa3bSJed Brown   PetscFunctionBegin;
50290a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50309566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50319566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(plex,&section));
50329566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dm,section));
50330a96aa3bSJed Brown   PetscFunctionReturn(0);
50340a96aa3bSJed Brown }
50350a96aa3bSJed Brown 
50360a96aa3bSJed Brown #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
50370a96aa3bSJed Brown static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
50380a96aa3bSJed Brown {
50390a96aa3bSJed Brown   DM             plex;
50400a96aa3bSJed Brown   Mat            mat;
504179769bd5SJed Brown   Vec            bias;
50420a96aa3bSJed Brown   PetscSection   section;
50430a96aa3bSJed Brown 
50440a96aa3bSJed Brown   PetscFunctionBegin;
50450a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50469566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50479566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(plex,&section,&mat,&bias));
50489566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm,section,mat,bias));
50490a96aa3bSJed Brown   PetscFunctionReturn(0);
50500a96aa3bSJed Brown }
50510a96aa3bSJed Brown 
50520a96aa3bSJed Brown #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
50530a96aa3bSJed Brown static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
50540a96aa3bSJed Brown {
50550a96aa3bSJed Brown   DM             plex;
50560a96aa3bSJed Brown 
50570a96aa3bSJed Brown   PetscFunctionBegin;
50580a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50599566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50609566063dSJacob Faibussowitsch   PetscCall(DMGetDimPoints(plex,dim,cStart,cEnd));
50610a96aa3bSJed Brown   PetscFunctionReturn(0);
50620a96aa3bSJed Brown }
50630a96aa3bSJed Brown 
50640a96aa3bSJed Brown /* Need to forward declare */
50650a96aa3bSJed Brown #define DMInitialize_pforest _append_pforest(DMInitialize)
50660a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
50670a96aa3bSJed Brown 
50680a96aa3bSJed Brown #define DMClone_pforest _append_pforest(DMClone)
50690a96aa3bSJed Brown static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
50700a96aa3bSJed Brown {
50710a96aa3bSJed Brown   PetscFunctionBegin;
50729566063dSJacob Faibussowitsch   PetscCall(DMClone_Forest(dm,newdm));
50739566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(*newdm));
50740a96aa3bSJed Brown   PetscFunctionReturn(0);
50750a96aa3bSJed Brown }
50760a96aa3bSJed Brown 
50770a96aa3bSJed Brown #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
50780a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
50790a96aa3bSJed Brown {
50800a96aa3bSJed Brown   DM_Forest         *forest;
50810a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50820a96aa3bSJed Brown   PetscInt          overlap;
50830a96aa3bSJed Brown 
50840a96aa3bSJed Brown   PetscFunctionBegin;
50859566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
50860a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
50870a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
50880a96aa3bSJed Brown   *cStart = 0;
50899566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
50900a96aa3bSJed Brown   if (overlap && pforest->ghost) {
50910a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
50920a96aa3bSJed Brown   } else {
50930a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
50940a96aa3bSJed Brown   }
50950a96aa3bSJed Brown   PetscFunctionReturn(0);
50960a96aa3bSJed Brown }
50970a96aa3bSJed Brown 
50980a96aa3bSJed Brown #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
50990a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
51000a96aa3bSJed Brown {
51010a96aa3bSJed Brown   DM_Forest         *forest;
51020a96aa3bSJed Brown   DM_Forest_pforest *pforest;
51030a96aa3bSJed Brown   PetscMPIInt       rank;
51040a96aa3bSJed Brown   PetscInt          overlap;
51050a96aa3bSJed Brown   PetscInt          cStart, cEnd, cLocalStart, cLocalEnd;
51060a96aa3bSJed Brown   PetscInt          nRoots, nLeaves, *mine = NULL;
51070a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
51080a96aa3bSJed Brown   PetscSF           sf;
51090a96aa3bSJed Brown 
51100a96aa3bSJed Brown   PetscFunctionBegin;
51119566063dSJacob Faibussowitsch   PetscCall(DMForestGetCellChart(dm,&cStart,&cEnd));
51120a96aa3bSJed Brown   forest      = (DM_Forest*)         dm->data;
51130a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
51140a96aa3bSJed Brown   nRoots      = cEnd - cStart;
51150a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
51160a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
51170a96aa3bSJed Brown   nLeaves     = 0;
51189566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
51199566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
51200a96aa3bSJed Brown   if (overlap && pforest->ghost) {
51210a96aa3bSJed Brown     PetscSFNode      *mirror;
51220a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
51230a96aa3bSJed Brown     PetscInt         nMirror, nGhostPre, nSelf, q;
51240a96aa3bSJed Brown     void             **mirrorPtrs;
51250a96aa3bSJed Brown 
51260a96aa3bSJed Brown     nMirror      = (PetscInt) pforest->ghost->mirrors.elem_count;
51270a96aa3bSJed Brown     nSelf        = cLocalEnd - cLocalStart;
51280a96aa3bSJed Brown     nLeaves      = nRoots - nSelf;
51290a96aa3bSJed Brown     nGhostPre    = (PetscInt) pforest->ghost->proc_offsets[rank];
51309566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves,&mine));
51319566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves,&remote));
51329566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nMirror,&mirror,nMirror,&mirrorPtrs));
51330a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t*) pforest->ghost->mirrors.array;
51340a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
51350a96aa3bSJed Brown       p4est_quadrant_t *mir = &(mirror_array[q]);
51360a96aa3bSJed Brown 
51370a96aa3bSJed Brown       mirror[q].rank  = rank;
51380a96aa3bSJed Brown       mirror[q].index = (PetscInt) mir->p.piggy3.local_num + cLocalStart;
51390a96aa3bSJed Brown       mirrorPtrs[q]   = (void*) &(mirror[q]);
51400a96aa3bSJed Brown     }
51410a96aa3bSJed Brown     PetscStackCallP4est(p4est_ghost_exchange_custom,(pforest->forest,pforest->ghost,sizeof(PetscSFNode),mirrorPtrs,remote));
51429566063dSJacob Faibussowitsch     PetscCall(PetscFree2(mirror,mirrorPtrs));
51430a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
51440a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
51450a96aa3bSJed Brown   }
51469566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&sf));
51479566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf,nRoots,nLeaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
51480a96aa3bSJed Brown   *cellSF = sf;
51490a96aa3bSJed Brown   PetscFunctionReturn(0);
51500a96aa3bSJed Brown }
51510a96aa3bSJed Brown 
51520a96aa3bSJed Brown static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS* ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void*), void **setup_ctx)
51530a96aa3bSJed Brown {
51540a96aa3bSJed Brown   DM             plex;
51550a96aa3bSJed Brown 
51560a96aa3bSJed Brown   PetscFunctionBegin;
51579566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
51589566063dSJacob Faibussowitsch   PetscCall(DMCreateNeumannOverlap_Plex(plex,ovl,J,setup,setup_ctx));
51590a96aa3bSJed Brown   if (!*setup) {
51609566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
51610a96aa3bSJed Brown     if (*setup) {
51629566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
51630a96aa3bSJed Brown     }
51640a96aa3bSJed Brown   }
51650a96aa3bSJed Brown   PetscFunctionReturn(0);
51660a96aa3bSJed Brown }
51670a96aa3bSJed Brown 
51680a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm)
51690a96aa3bSJed Brown {
51700a96aa3bSJed Brown   PetscFunctionBegin;
51710a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
51720a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
51730a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
51740a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
51750a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
51760a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
51770a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
51780a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
51790a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
51800a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
51810a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
51820a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
51830a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
51840a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
51850a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
51860a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
51870a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
51880a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
51890a96aa3bSJed Brown 
51909566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",DMConvert_plex_pforest));
51919566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",DMConvert_pforest_plex));
51929566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_pforest));
51939566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMForestGetPartitionOverlap));
51940a96aa3bSJed Brown   PetscFunctionReturn(0);
51950a96aa3bSJed Brown }
51960a96aa3bSJed Brown 
51970a96aa3bSJed Brown #define DMCreate_pforest _append_pforest(DMCreate)
51980a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
51990a96aa3bSJed Brown {
52000a96aa3bSJed Brown   DM_Forest         *forest;
52010a96aa3bSJed Brown   DM_Forest_pforest *pforest;
52020a96aa3bSJed Brown 
52030a96aa3bSJed Brown   PetscFunctionBegin;
52049566063dSJacob Faibussowitsch   PetscCall(PetscP4estInitialize());
52059566063dSJacob Faibussowitsch   PetscCall(DMCreate_Forest(dm));
52069566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(dm));
52079566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm,P4EST_DIM));
52080a96aa3bSJed Brown 
52090a96aa3bSJed Brown   /* set forest defaults */
52109566063dSJacob Faibussowitsch   PetscCall(DMForestSetTopology(dm,"unit"));
52119566063dSJacob Faibussowitsch   PetscCall(DMForestSetMinimumRefinement(dm,0));
52129566063dSJacob Faibussowitsch   PetscCall(DMForestSetInitialRefinement(dm,0));
52139566063dSJacob Faibussowitsch   PetscCall(DMForestSetMaximumRefinement(dm,P4EST_QMAXLEVEL));
52149566063dSJacob Faibussowitsch   PetscCall(DMForestSetGradeFactor(dm,2));
52159566063dSJacob Faibussowitsch   PetscCall(DMForestSetAdjacencyDimension(dm,0));
52169566063dSJacob Faibussowitsch   PetscCall(DMForestSetPartitionOverlap(dm,0));
52170a96aa3bSJed Brown 
52180a96aa3bSJed Brown   /* create p4est data */
52199566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(dm,&pforest));
52200a96aa3bSJed Brown 
52210a96aa3bSJed Brown   forest                            = (DM_Forest*) dm->data;
52220a96aa3bSJed Brown   forest->data                      = pforest;
52230a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
52240a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
52250a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
52260a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
52270a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
52280a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
52290a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
52300a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
52310a96aa3bSJed Brown   pforest->topo                     = NULL;
52320a96aa3bSJed Brown   pforest->forest                   = NULL;
52330a96aa3bSJed Brown   pforest->ghost                    = NULL;
52340a96aa3bSJed Brown   pforest->lnodes                   = NULL;
52350a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
52360a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
52370a96aa3bSJed Brown   pforest->cLocalStart              = -1;
52380a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
52390a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
52400a96aa3bSJed Brown   pforest->ghostName                = NULL;
52410a96aa3bSJed Brown   PetscFunctionReturn(0);
52420a96aa3bSJed Brown }
52430a96aa3bSJed Brown 
52440a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5245