xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 2e956fe4fc852fabc23b437482e1fb7b77fddb0d)
10a96aa3bSJed Brown #include <petscds.h>
20a96aa3bSJed Brown #include <petsc/private/dmimpl.h>
30a96aa3bSJed Brown #include <petsc/private/dmforestimpl.h>
40a96aa3bSJed Brown #include <petsc/private/dmpleximpl.h>
50a96aa3bSJed Brown #include <petsc/private/dmlabelimpl.h>
60a96aa3bSJed Brown #include <petsc/private/viewerimpl.h>
70a96aa3bSJed Brown #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h>
80a96aa3bSJed Brown #include "petsc_p4est_package.h"
90a96aa3bSJed Brown 
100a96aa3bSJed Brown #if defined(PETSC_HAVE_P4EST)
110a96aa3bSJed Brown 
120a96aa3bSJed Brown #if !defined(P4_TO_P8)
130a96aa3bSJed Brown #include <p4est.h>
140a96aa3bSJed Brown #include <p4est_extended.h>
150a96aa3bSJed Brown #include <p4est_geometry.h>
160a96aa3bSJed Brown #include <p4est_ghost.h>
170a96aa3bSJed Brown #include <p4est_lnodes.h>
180a96aa3bSJed Brown #include <p4est_vtk.h>
190a96aa3bSJed Brown #include <p4est_plex.h>
200a96aa3bSJed Brown #include <p4est_bits.h>
210a96aa3bSJed Brown #include <p4est_algorithms.h>
220a96aa3bSJed Brown #else
230a96aa3bSJed Brown #include <p8est.h>
240a96aa3bSJed Brown #include <p8est_extended.h>
250a96aa3bSJed Brown #include <p8est_geometry.h>
260a96aa3bSJed Brown #include <p8est_ghost.h>
270a96aa3bSJed Brown #include <p8est_lnodes.h>
280a96aa3bSJed Brown #include <p8est_vtk.h>
290a96aa3bSJed Brown #include <p8est_plex.h>
300a96aa3bSJed Brown #include <p8est_bits.h>
310a96aa3bSJed Brown #include <p8est_algorithms.h>
320a96aa3bSJed Brown #endif
330a96aa3bSJed Brown 
340a96aa3bSJed Brown typedef enum {PATTERN_HASH,PATTERN_FRACTAL,PATTERN_CORNER,PATTERN_CENTER,PATTERN_COUNT} DMRefinePattern;
350a96aa3bSJed Brown static const char *DMRefinePatternName[PATTERN_COUNT] = {"hash","fractal","corner","center"};
360a96aa3bSJed Brown 
370a96aa3bSJed Brown typedef struct _DMRefinePatternCtx
380a96aa3bSJed Brown {
390a96aa3bSJed Brown   PetscInt       corner;
400a96aa3bSJed Brown   PetscBool      fractal[P4EST_CHILDREN];
410a96aa3bSJed Brown   PetscReal      hashLikelihood;
420a96aa3bSJed Brown   PetscInt       maxLevel;
430a96aa3bSJed Brown   p4est_refine_t refine_fn;
440a96aa3bSJed Brown }
450a96aa3bSJed Brown DMRefinePatternCtx;
460a96aa3bSJed Brown 
470a96aa3bSJed Brown static int DMRefinePattern_Corner(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
480a96aa3bSJed Brown {
490a96aa3bSJed Brown   p4est_quadrant_t   root, rootcorner;
500a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
510a96aa3bSJed Brown 
520a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
530a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
540a96aa3bSJed Brown 
550a96aa3bSJed Brown   root.x = root.y = 0;
560a96aa3bSJed Brown #if defined(P4_TO_P8)
570a96aa3bSJed Brown   root.z = 0;
580a96aa3bSJed Brown #endif
590a96aa3bSJed Brown   root.level = 0;
600a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&root,&rootcorner,ctx->corner,quadrant->level);
610a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant,&rootcorner)) return 1;
620a96aa3bSJed Brown   return 0;
630a96aa3bSJed Brown }
640a96aa3bSJed Brown 
650a96aa3bSJed Brown static int DMRefinePattern_Center(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
660a96aa3bSJed Brown {
670a96aa3bSJed Brown   int                cid;
680a96aa3bSJed Brown   p4est_quadrant_t   ancestor, ancestorcorner;
690a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
700a96aa3bSJed Brown 
710a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
720a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
730a96aa3bSJed Brown   if (quadrant->level <= 1) return 1;
740a96aa3bSJed Brown 
750a96aa3bSJed Brown   p4est_quadrant_ancestor(quadrant,1,&ancestor);
760a96aa3bSJed Brown   cid = p4est_quadrant_child_id(&ancestor);
770a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&ancestor,&ancestorcorner,P4EST_CHILDREN - 1 - cid,quadrant->level);
780a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant,&ancestorcorner)) return 1;
790a96aa3bSJed Brown   return 0;
800a96aa3bSJed Brown }
810a96aa3bSJed Brown 
820a96aa3bSJed Brown static int DMRefinePattern_Fractal(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
830a96aa3bSJed Brown {
840a96aa3bSJed Brown   int                cid;
850a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
860a96aa3bSJed Brown 
870a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
880a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
890a96aa3bSJed Brown   if (!quadrant->level) return 1;
900a96aa3bSJed Brown   cid = p4est_quadrant_child_id(quadrant);
910a96aa3bSJed Brown   if (ctx->fractal[cid ^ ((int) (quadrant->level % P4EST_CHILDREN))]) return 1;
920a96aa3bSJed Brown   return 0;
930a96aa3bSJed Brown }
940a96aa3bSJed Brown 
950a96aa3bSJed Brown /* simplified from MurmurHash3 by Austin Appleby */
960a96aa3bSJed Brown #define DMPROT32(x, y) ((x << y) | (x >> (32 - y)))
970a96aa3bSJed Brown static uint32_t DMPforestHash(const uint32_t *blocks, uint32_t nblocks)
980a96aa3bSJed Brown {
990a96aa3bSJed Brown   uint32_t c1   = 0xcc9e2d51;
1000a96aa3bSJed Brown   uint32_t c2   = 0x1b873593;
1010a96aa3bSJed Brown   uint32_t r1   = 15;
1020a96aa3bSJed Brown   uint32_t r2   = 13;
1030a96aa3bSJed Brown   uint32_t m    = 5;
1040a96aa3bSJed Brown   uint32_t n    = 0xe6546b64;
1050a96aa3bSJed Brown   uint32_t hash = 0;
1060a96aa3bSJed Brown   int      len  = nblocks * 4;
1070a96aa3bSJed Brown   uint32_t i;
1080a96aa3bSJed Brown 
1090a96aa3bSJed Brown   for (i = 0; i < nblocks; i++) {
1100a96aa3bSJed Brown     uint32_t k;
1110a96aa3bSJed Brown 
1120a96aa3bSJed Brown     k  = blocks[i];
1130a96aa3bSJed Brown     k *= c1;
1140a96aa3bSJed Brown     k  = DMPROT32(k, r1);
1150a96aa3bSJed Brown     k *= c2;
1160a96aa3bSJed Brown 
1170a96aa3bSJed Brown     hash ^= k;
1180a96aa3bSJed Brown     hash  = DMPROT32(hash, r2) * m + n;
1190a96aa3bSJed Brown   }
1200a96aa3bSJed Brown 
1210a96aa3bSJed Brown   hash ^= len;
1220a96aa3bSJed Brown   hash ^= (hash >> 16);
1230a96aa3bSJed Brown   hash *= 0x85ebca6b;
1240a96aa3bSJed Brown   hash ^= (hash >> 13);
1250a96aa3bSJed Brown   hash *= 0xc2b2ae35;
1260a96aa3bSJed Brown   hash ^= (hash >> 16);
1270a96aa3bSJed Brown 
1280a96aa3bSJed Brown   return hash;
1290a96aa3bSJed Brown }
1300a96aa3bSJed Brown 
1310a96aa3bSJed Brown #if defined(UINT32_MAX)
1320a96aa3bSJed Brown #define DMP4EST_HASH_MAX UINT32_MAX
1330a96aa3bSJed Brown #else
1340a96aa3bSJed Brown #define DMP4EST_HASH_MAX ((uint32_t) 0xffffffff)
1350a96aa3bSJed Brown #endif
1360a96aa3bSJed Brown 
1370a96aa3bSJed Brown static int DMRefinePattern_Hash(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
1380a96aa3bSJed Brown {
1390a96aa3bSJed Brown   uint32_t           data[5];
1400a96aa3bSJed Brown   uint32_t           result;
1410a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
1420a96aa3bSJed Brown 
1430a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
1440a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
1450a96aa3bSJed Brown   data[0] = ((uint32_t) quadrant->level) << 24;
1460a96aa3bSJed Brown   data[1] = (uint32_t) which_tree;
1470a96aa3bSJed Brown   data[2] = (uint32_t) quadrant->x;
1480a96aa3bSJed Brown   data[3] = (uint32_t) quadrant->y;
1490a96aa3bSJed Brown #if defined(P4_TO_P8)
1500a96aa3bSJed Brown   data[4] = (uint32_t) quadrant->z;
1510a96aa3bSJed Brown #endif
1520a96aa3bSJed Brown 
1530a96aa3bSJed Brown   result = DMPforestHash(data,2+P4EST_DIM);
1540a96aa3bSJed Brown   if (((double) result / (double) DMP4EST_HASH_MAX) < ctx->hashLikelihood) return 1;
1550a96aa3bSJed Brown   return 0;
1560a96aa3bSJed Brown }
1570a96aa3bSJed Brown 
1580a96aa3bSJed Brown #define DMConvert_pforest_plex _infix_pforest(DMConvert,_plex)
1590a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM,DMType,DM*);
1600a96aa3bSJed Brown 
1610a96aa3bSJed Brown #define DMFTopology_pforest _append_pforest(DMFTopology)
1620a96aa3bSJed Brown typedef struct {
1630a96aa3bSJed Brown   PetscInt             refct;
1640a96aa3bSJed Brown   p4est_connectivity_t *conn;
1650a96aa3bSJed Brown   p4est_geometry_t     *geom;
1660a96aa3bSJed Brown   PetscInt             *tree_face_to_uniq; /* p4est does not explicitly enumerate facets, but we must to keep track of labels */
1670a96aa3bSJed Brown } DMFTopology_pforest;
1680a96aa3bSJed Brown 
1690a96aa3bSJed Brown #define DM_Forest_pforest _append_pforest(DM_Forest)
1700a96aa3bSJed Brown typedef struct {
1710a96aa3bSJed Brown   DMFTopology_pforest *topo;
1720a96aa3bSJed Brown   p4est_t             *forest;
1730a96aa3bSJed Brown   p4est_ghost_t       *ghost;
1740a96aa3bSJed Brown   p4est_lnodes_t      *lnodes;
1750a96aa3bSJed Brown   PetscBool           partition_for_coarsening;
1760a96aa3bSJed Brown   PetscBool           coarsen_hierarchy;
1770a96aa3bSJed Brown   PetscBool           labelsFinalized;
1780a96aa3bSJed Brown   PetscBool           adaptivitySuccess;
1790a96aa3bSJed Brown   PetscInt            cLocalStart;
1800a96aa3bSJed Brown   PetscInt            cLocalEnd;
1810a96aa3bSJed Brown   DM                  plex;
1820a96aa3bSJed Brown   char                *ghostName;
1830a96aa3bSJed Brown   PetscSF             pointAdaptToSelfSF;
1840a96aa3bSJed Brown   PetscSF             pointSelfToAdaptSF;
1850a96aa3bSJed Brown   PetscInt            *pointAdaptToSelfCids;
1860a96aa3bSJed Brown   PetscInt            *pointSelfToAdaptCids;
1870a96aa3bSJed Brown } DM_Forest_pforest;
1880a96aa3bSJed Brown 
1890a96aa3bSJed Brown #define DM_Forest_geometry_pforest _append_pforest(DM_Forest_geometry)
1900a96aa3bSJed Brown typedef struct {
1910a96aa3bSJed Brown   DM base;
1920a96aa3bSJed Brown   PetscErrorCode   (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void*);
1930a96aa3bSJed Brown   void             *mapCtx;
1940a96aa3bSJed Brown   PetscInt         coordDim;
1950a96aa3bSJed Brown   p4est_geometry_t *inner;
1960a96aa3bSJed Brown }
1970a96aa3bSJed Brown DM_Forest_geometry_pforest;
1980a96aa3bSJed Brown 
1990a96aa3bSJed Brown #define GeometryMapping_pforest _append_pforest(GeometryMapping)
2000a96aa3bSJed Brown static void GeometryMapping_pforest(p4est_geometry_t *geom, p4est_topidx_t which_tree, const double abc[3], double xyz[3])
2010a96aa3bSJed Brown {
2020a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user;
2030a96aa3bSJed Brown   PetscReal                  PetscABC[3]   = {0.};
2040a96aa3bSJed Brown   PetscReal                  PetscXYZ[3]   = {0.};
2050a96aa3bSJed Brown   PetscInt                   i, d = PetscMin(3,geom_pforest->coordDim);
2060a96aa3bSJed Brown   double                     ABC[3];
2070a96aa3bSJed Brown   PetscErrorCode             ierr;
2080a96aa3bSJed Brown 
2090a96aa3bSJed Brown   (geom_pforest->inner->X)(geom_pforest->inner,which_tree,abc,ABC);
2100a96aa3bSJed Brown 
2110a96aa3bSJed Brown   for (i = 0; i < d; i++) PetscABC[i] = ABC[i];
2120a96aa3bSJed Brown   ierr = (geom_pforest->map)(geom_pforest->base,(PetscInt) which_tree,geom_pforest->coordDim,PetscABC,PetscXYZ,geom_pforest->mapCtx);PETSC_P4EST_ASSERT(!ierr);
2130a96aa3bSJed Brown   for (i = 0; i < d; i++) xyz[i] = PetscXYZ[i];
2140a96aa3bSJed Brown }
2150a96aa3bSJed Brown 
2160a96aa3bSJed Brown #define GeometryDestroy_pforest _append_pforest(GeometryDestroy)
2170a96aa3bSJed Brown static void GeometryDestroy_pforest(p4est_geometry_t *geom)
2180a96aa3bSJed Brown {
2190a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user;
2200a96aa3bSJed Brown   PetscErrorCode             ierr;
2210a96aa3bSJed Brown 
2220a96aa3bSJed Brown   p4est_geometry_destroy(geom_pforest->inner);
2230a96aa3bSJed Brown   ierr = PetscFree(geom->user);PETSC_P4EST_ASSERT(!ierr);
2240a96aa3bSJed Brown   ierr = PetscFree(geom);PETSC_P4EST_ASSERT(!ierr);
2250a96aa3bSJed Brown }
2260a96aa3bSJed Brown 
2270a96aa3bSJed Brown #define DMFTopologyDestroy_pforest _append_pforest(DMFTopologyDestroy)
2280a96aa3bSJed Brown static PetscErrorCode DMFTopologyDestroy_pforest(DMFTopology_pforest **topo)
2290a96aa3bSJed Brown {
2300a96aa3bSJed Brown   PetscFunctionBegin;
2310a96aa3bSJed Brown   if (!(*topo)) PetscFunctionReturn(0);
2320a96aa3bSJed Brown   if (--((*topo)->refct) > 0) {
2330a96aa3bSJed Brown     *topo = NULL;
2340a96aa3bSJed Brown     PetscFunctionReturn(0);
2350a96aa3bSJed Brown   }
2360a96aa3bSJed Brown   if ((*topo)->geom) PetscStackCallP4est(p4est_geometry_destroy,((*topo)->geom));
2370a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,((*topo)->conn));
2389566063dSJacob Faibussowitsch   PetscCall(PetscFree((*topo)->tree_face_to_uniq));
2399566063dSJacob Faibussowitsch   PetscCall(PetscFree(*topo));
2400a96aa3bSJed Brown   *topo = NULL;
2410a96aa3bSJed Brown   PetscFunctionReturn(0);
2420a96aa3bSJed Brown }
2430a96aa3bSJed Brown 
2440a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t*,PetscInt**);
2450a96aa3bSJed Brown 
2460a96aa3bSJed Brown #define DMFTopologyCreateBrick_pforest _append_pforest(DMFTopologyCreateBrick)
2470a96aa3bSJed Brown static PetscErrorCode DMFTopologyCreateBrick_pforest(DM dm,PetscInt N[], PetscInt P[], PetscReal B[],DMFTopology_pforest **topo, PetscBool useMorton)
2480a96aa3bSJed Brown {
2490a96aa3bSJed Brown   double         *vertices;
2500a96aa3bSJed Brown   PetscInt       i, numVerts;
2510a96aa3bSJed Brown 
2520a96aa3bSJed Brown   PetscFunctionBegin;
25328b400f6SJacob Faibussowitsch   PetscCheck(useMorton,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Lexicographic ordering not implemented yet");
2549566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(dm,topo));
2550a96aa3bSJed Brown 
2560a96aa3bSJed Brown   (*topo)->refct = 1;
2570a96aa3bSJed Brown #if !defined(P4_TO_P8)
2580a96aa3bSJed Brown   PetscStackCallP4estReturn((*topo)->conn,p4est_connectivity_new_brick,((int) N[0], (int) N[1], (P[0] == DM_BOUNDARY_NONE) ? 0 : 1, (P[1] == DM_BOUNDARY_NONE) ? 0 : 1));
2590a96aa3bSJed Brown #else
2600a96aa3bSJed Brown   PetscStackCallP4estReturn((*topo)->conn,p8est_connectivity_new_brick,((int) N[0], (int) N[1], (int) N[2], (P[0] == DM_BOUNDARY_NONE) ? 0 : 1, (P[1] == DM_BOUNDARY_NONE) ? 0 : 1, (P[2] == DM_BOUNDARY_NONE) ? 0 : 1));
2610a96aa3bSJed Brown #endif
2620a96aa3bSJed Brown   numVerts = (*topo)->conn->num_vertices;
2630a96aa3bSJed Brown   vertices = (*topo)->conn->vertices;
2640a96aa3bSJed Brown   for (i = 0; i < 3 * numVerts; i++) {
2650a96aa3bSJed Brown     PetscInt j = i % 3;
2660a96aa3bSJed Brown 
2670a96aa3bSJed Brown     vertices[i] = B[2 * j] + (vertices[i]/N[j]) * (B[2 * j + 1] - B[2 * j]);
2680a96aa3bSJed Brown   }
2690a96aa3bSJed Brown   (*topo)->geom = NULL;
2709566063dSJacob Faibussowitsch   PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq));
2710a96aa3bSJed Brown   PetscFunctionReturn(0);
2720a96aa3bSJed Brown }
2730a96aa3bSJed Brown 
2740a96aa3bSJed Brown #define DMFTopologyCreate_pforest _append_pforest(DMFTopologyCreate)
2750a96aa3bSJed Brown static PetscErrorCode DMFTopologyCreate_pforest(DM dm, DMForestTopology topologyName, DMFTopology_pforest **topo)
2760a96aa3bSJed Brown {
2770a96aa3bSJed Brown   const char     *name = (const char*) topologyName;
2780a96aa3bSJed Brown   const char     *prefix;
2790a96aa3bSJed Brown   PetscBool      isBrick, isShell, isSphere, isMoebius;
2800a96aa3bSJed Brown 
2810a96aa3bSJed Brown   PetscFunctionBegin;
2820a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
2830a96aa3bSJed Brown   PetscValidCharPointer(name,2);
2840a96aa3bSJed Brown   PetscValidPointer(topo,3);
2859566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"brick",&isBrick));
2869566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"shell",&isShell));
2879566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"sphere",&isSphere));
2889566063dSJacob Faibussowitsch   PetscCall(PetscStrcmp(name,"moebius",&isMoebius));
2899566063dSJacob Faibussowitsch   PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
2900a96aa3bSJed Brown   if (isBrick) {
2910a96aa3bSJed Brown     PetscBool flgN, flgP, flgM, flgB, useMorton = PETSC_TRUE, periodic = PETSC_FALSE;
2920a96aa3bSJed Brown     PetscInt  N[3] = {2,2,2}, P[3] = {0,0,0}, nretN = P4EST_DIM, nretP = P4EST_DIM, nretB = 2 * P4EST_DIM, i;
2930a96aa3bSJed Brown     PetscReal B[6] = {0.0,1.0,0.0,1.0,0.0,1.0};
2940a96aa3bSJed Brown 
2950a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
2969566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_size",N,&nretN,&flgN));
2979566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_periodicity",P,&nretP,&flgP));
2989566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetRealArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_bounds",B,&nretB,&flgB));
2999566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_use_morton_curve",&useMorton,&flgM));
3001dca8a05SBarry Smith       PetscCheck(!flgN || nretN == P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d sizes in -dm_p4est_brick_size, gave %" PetscInt_FMT,P4EST_DIM,nretN);
3011dca8a05SBarry Smith       PetscCheck(!flgP || nretP == P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d periodicities in -dm_p4est_brick_periodicity, gave %" PetscInt_FMT,P4EST_DIM,nretP);
3021dca8a05SBarry Smith       PetscCheck(!flgB || nretB == 2 * P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d bounds in -dm_p4est_brick_bounds, gave %" PetscInt_FMT,P4EST_DIM,nretP);
3030a96aa3bSJed Brown     }
3040a96aa3bSJed Brown     for (i = 0; i < P4EST_DIM; i++) {
3050a96aa3bSJed Brown       P[i]  = (P[i] ? DM_BOUNDARY_PERIODIC : DM_BOUNDARY_NONE);
3060a96aa3bSJed Brown       periodic = (PetscBool)(P[i] || periodic);
3070a96aa3bSJed Brown       if (!flgB) B[2 * i + 1] = N[i];
3080a96aa3bSJed Brown     }
3099566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,B,topo,useMorton));
3100a96aa3bSJed Brown     /* the maxCell trick is not robust enough, localize on all cells if periodic */
3119566063dSJacob Faibussowitsch     PetscCall(DMSetPeriodicity(dm,periodic,NULL,NULL,NULL));
3120a96aa3bSJed Brown   } else {
3139566063dSJacob Faibussowitsch     PetscCall(PetscNewLog(dm,topo));
3140a96aa3bSJed Brown 
3150a96aa3bSJed Brown     (*topo)->refct = 1;
3160a96aa3bSJed Brown     PetscStackCallP4estReturn((*topo)->conn,p4est_connectivity_new_byname,(name));
3170a96aa3bSJed Brown     (*topo)->geom = NULL;
3180a96aa3bSJed Brown     if (isMoebius) {
3199566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinateDim(dm,3));
3200a96aa3bSJed Brown     }
3210a96aa3bSJed Brown #if defined(P4_TO_P8)
3220a96aa3bSJed Brown     if (isShell) {
3230a96aa3bSJed Brown       PetscReal R2 = 1., R1 = .55;
3240a96aa3bSJed Brown 
3250a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3269566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_outer_radius",&R2,NULL));
3279566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_inner_radius",&R1,NULL));
3280a96aa3bSJed Brown       }
3290a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_shell,((*topo)->conn,R2,R1));
3300a96aa3bSJed Brown     } else if (isSphere) {
3310a96aa3bSJed Brown       PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856;
3320a96aa3bSJed Brown 
3330a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
3349566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_outer_radius",&R2,NULL));
3359566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_inner_radius",&R1,NULL));
3369566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_core_radius",&R0,NULL));
3370a96aa3bSJed Brown       }
3380a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_sphere,((*topo)->conn,R2,R1,R0));
3390a96aa3bSJed Brown     }
3400a96aa3bSJed Brown #endif
3419566063dSJacob Faibussowitsch     PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq));
3420a96aa3bSJed Brown   }
3430a96aa3bSJed Brown   PetscFunctionReturn(0);
3440a96aa3bSJed Brown }
3450a96aa3bSJed Brown 
3460a96aa3bSJed Brown #define DMConvert_plex_pforest _append_pforest(DMConvert_plex)
3470a96aa3bSJed Brown static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest)
3480a96aa3bSJed Brown {
3490a96aa3bSJed Brown   MPI_Comm       comm;
3500a96aa3bSJed Brown   PetscBool      isPlex;
3510a96aa3bSJed Brown   PetscInt       dim;
3520a96aa3bSJed Brown   void           *ctx;
3530a96aa3bSJed Brown 
3540a96aa3bSJed Brown   PetscFunctionBegin;
3550a96aa3bSJed Brown 
3560a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3570a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
3589566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex));
35928b400f6SJacob Faibussowitsch   PetscCheck(isPlex,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPLEX,((PetscObject)dm)->type_name);
3609566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dim));
36163a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim);
3629566063dSJacob Faibussowitsch   PetscCall(DMCreate(comm,pforest));
3639566063dSJacob Faibussowitsch   PetscCall(DMSetType(*pforest,DMPFOREST));
3649566063dSJacob Faibussowitsch   PetscCall(DMForestSetBaseDM(*pforest,dm));
3659566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dm,&ctx));
3669566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(*pforest,ctx));
3679566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dm,*pforest));
3680a96aa3bSJed Brown   PetscFunctionReturn(0);
3690a96aa3bSJed Brown }
3700a96aa3bSJed Brown 
3710a96aa3bSJed Brown #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
3720a96aa3bSJed Brown static PetscErrorCode DMForestDestroy_pforest(DM dm)
3730a96aa3bSJed Brown {
3740a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
3750a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
3760a96aa3bSJed Brown 
3770a96aa3bSJed Brown   PetscFunctionBegin;
3780a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
3790a96aa3bSJed Brown   if (pforest->lnodes) PetscStackCallP4est(p4est_lnodes_destroy,(pforest->lnodes));
3800a96aa3bSJed Brown   pforest->lnodes = NULL;
3810a96aa3bSJed Brown   if (pforest->ghost) PetscStackCallP4est(p4est_ghost_destroy,(pforest->ghost));
3820a96aa3bSJed Brown   pforest->ghost = NULL;
3830a96aa3bSJed Brown   if (pforest->forest) PetscStackCallP4est(p4est_destroy,(pforest->forest));
3840a96aa3bSJed Brown   pforest->forest = NULL;
3859566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&pforest->topo));
3869566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",NULL));
3879566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",NULL));
388*2e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL));
3899566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",NULL));
390*2e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL));
391*2e956fe4SStefano Zampini   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL));
3929566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->ghostName));
3939566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&pforest->plex));
3949566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF));
3959566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF));
3969566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
3979566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
3989566063dSJacob Faibussowitsch   PetscCall(PetscFree(forest->data));
3990a96aa3bSJed Brown   PetscFunctionReturn(0);
4000a96aa3bSJed Brown }
4010a96aa3bSJed Brown 
4020a96aa3bSJed Brown #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
4030a96aa3bSJed Brown static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm)
4040a96aa3bSJed Brown {
4050a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4060a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest*) ((DM_Forest*) tdm->data)->data;
4070a96aa3bSJed Brown 
4080a96aa3bSJed Brown   PetscFunctionBegin;
4090a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
4109566063dSJacob Faibussowitsch   PetscCall(DMFTopologyDestroy_pforest(&(tpforest->topo)));
4110a96aa3bSJed Brown   tpforest->topo = pforest->topo;
4120a96aa3bSJed Brown   PetscFunctionReturn(0);
4130a96aa3bSJed Brown }
4140a96aa3bSJed Brown 
4150a96aa3bSJed Brown #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
4160a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM,p4est_connectivity_t**,PetscInt**);
4170a96aa3bSJed Brown 
4180a96aa3bSJed Brown typedef struct _PforestAdaptCtx
4190a96aa3bSJed Brown {
4200a96aa3bSJed Brown   PetscInt  maxLevel;
4210a96aa3bSJed Brown   PetscInt  minLevel;
4220a96aa3bSJed Brown   PetscInt  currLevel;
4230a96aa3bSJed Brown   PetscBool anyChange;
4240a96aa3bSJed Brown }
4250a96aa3bSJed Brown PforestAdaptCtx;
4260a96aa3bSJed Brown 
4270a96aa3bSJed Brown static int pforest_coarsen_currlevel(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4280a96aa3bSJed Brown {
4290a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx*) p4est->user_pointer;
4300a96aa3bSJed Brown   PetscInt        minLevel  = ctx->minLevel;
4310a96aa3bSJed Brown   PetscInt        currLevel = ctx->currLevel;
4320a96aa3bSJed Brown 
4330a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4340a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level == currLevel);
4350a96aa3bSJed Brown }
4360a96aa3bSJed Brown 
4370a96aa3bSJed Brown static int pforest_coarsen_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4380a96aa3bSJed Brown {
4390a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4400a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4410a96aa3bSJed Brown 
4420a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level > minLevel);
4430a96aa3bSJed Brown }
4440a96aa3bSJed Brown 
4450a96aa3bSJed Brown static int pforest_coarsen_flag_any(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4460a96aa3bSJed Brown {
4470a96aa3bSJed Brown   PetscInt        i;
4480a96aa3bSJed Brown   PetscBool       any      = PETSC_FALSE;
4490a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4500a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4510a96aa3bSJed Brown 
4520a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4530a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4540a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
4550a96aa3bSJed Brown       any = PETSC_FALSE;
4560a96aa3bSJed Brown       break;
4570a96aa3bSJed Brown     }
4580a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
4590a96aa3bSJed Brown       any = PETSC_TRUE;
4600a96aa3bSJed Brown       break;
4610a96aa3bSJed Brown     }
4620a96aa3bSJed Brown   }
4630a96aa3bSJed Brown   return any ? 1 : 0;
4640a96aa3bSJed Brown }
4650a96aa3bSJed Brown 
4660a96aa3bSJed Brown static int pforest_coarsen_flag_all(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
4670a96aa3bSJed Brown {
4680a96aa3bSJed Brown   PetscInt        i;
4690a96aa3bSJed Brown   PetscBool       all      = PETSC_TRUE;
4700a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4710a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
4720a96aa3bSJed Brown 
4730a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
4740a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
4750a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
4760a96aa3bSJed Brown       all = PETSC_FALSE;
4770a96aa3bSJed Brown       break;
4780a96aa3bSJed Brown     }
4790a96aa3bSJed Brown   }
4800a96aa3bSJed Brown   return all ? 1 : 0;
4810a96aa3bSJed Brown }
4820a96aa3bSJed Brown 
4830a96aa3bSJed Brown static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4840a96aa3bSJed Brown {
4850a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
4860a96aa3bSJed Brown }
4870a96aa3bSJed Brown 
4880a96aa3bSJed Brown static int pforest_refine_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4890a96aa3bSJed Brown {
4900a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4910a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
4920a96aa3bSJed Brown 
4930a96aa3bSJed Brown   return ((PetscInt) quadrant->level < maxLevel);
4940a96aa3bSJed Brown }
4950a96aa3bSJed Brown 
4960a96aa3bSJed Brown static int pforest_refine_flag(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
4970a96aa3bSJed Brown {
4980a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
4990a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
5000a96aa3bSJed Brown 
5010a96aa3bSJed Brown   if ((PetscInt) quadrant->level >= maxLevel) return 0;
5020a96aa3bSJed Brown 
5030a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
5040a96aa3bSJed Brown }
5050a96aa3bSJed Brown 
5060a96aa3bSJed 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)
5070a96aa3bSJed Brown {
5080a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
5090a96aa3bSJed Brown   p4est_topidx_t t;
5100a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
5110a96aa3bSJed Brown 
5120a96aa3bSJed Brown   PetscFunctionBegin;
5130a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
5140a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t*) p4estFrom->trees->array)[t]);
5150a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t*) p4estTo->trees->array)[t]);
5160a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
5170a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
5180a96aa3bSJed Brown     PetscInt         numFrom    = (PetscInt) treeFrom->quadrants.elem_count;
5190a96aa3bSJed Brown     PetscInt         numTo      = (PetscInt) treeTo->quadrants.elem_count;
5200a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t*) treeFrom->quadrants.array;
5210a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t*) treeTo->quadrants.array;
5220a96aa3bSJed Brown     PetscInt         currentFrom, currentTo;
5230a96aa3bSJed Brown     PetscInt         treeOffsetFrom = (PetscInt) treeFrom->quadrants_offset;
5240a96aa3bSJed Brown     PetscInt         treeOffsetTo   = (PetscInt) treeTo->quadrants_offset;
5250a96aa3bSJed Brown     int              comp;
5260a96aa3bSJed Brown 
5270a96aa3bSJed Brown     PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(firstFrom,firstTo));
52828b400f6SJacob Faibussowitsch     PetscCheck(comp,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"non-matching partitions");
5290a96aa3bSJed Brown 
5300a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
5310a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
5320a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
5330a96aa3bSJed Brown 
5340a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
5350a96aa3bSJed Brown         if (toLeaves) {
5360a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5370a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
5380a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5390a96aa3bSJed Brown         }
5400a96aa3bSJed Brown         toFineLeaves++;
5410a96aa3bSJed Brown         currentFrom++;
5420a96aa3bSJed Brown         currentTo++;
5430a96aa3bSJed Brown       } else {
5440a96aa3bSJed Brown         int fromIsAncestor;
5450a96aa3bSJed Brown 
5460a96aa3bSJed Brown         PetscStackCallP4estReturn(fromIsAncestor,p4est_quadrant_is_ancestor,(quadFrom,quadTo));
5470a96aa3bSJed Brown         if (fromIsAncestor) {
5480a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5490a96aa3bSJed Brown 
5500a96aa3bSJed Brown           if (toLeaves) {
5510a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
5520a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
5530a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
5540a96aa3bSJed Brown           }
5550a96aa3bSJed Brown           toFineLeaves++;
5560a96aa3bSJed Brown           currentTo++;
5570a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadFrom,&lastDesc,quadTo->level));
5580a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadTo,&lastDesc));
5590a96aa3bSJed Brown           if (comp) currentFrom++;
5600a96aa3bSJed Brown         } else {
5610a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
5620a96aa3bSJed Brown 
5630a96aa3bSJed Brown           if (fromLeaves) {
5640a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
5650a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
5660a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
5670a96aa3bSJed Brown           }
5680a96aa3bSJed Brown           fromFineLeaves++;
5690a96aa3bSJed Brown           currentFrom++;
5700a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadTo,&lastDesc,quadFrom->level));
5710a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadFrom,&lastDesc));
5720a96aa3bSJed Brown           if (comp) currentTo++;
5730a96aa3bSJed Brown         }
5740a96aa3bSJed Brown       }
5750a96aa3bSJed Brown     }
5760a96aa3bSJed Brown   }
5770a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
5780a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
5790a96aa3bSJed Brown   PetscFunctionReturn(0);
5800a96aa3bSJed Brown }
5810a96aa3bSJed Brown 
5820a96aa3bSJed Brown /* Compute the maximum level across all the trees */
5830a96aa3bSJed Brown static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev)
5840a96aa3bSJed Brown {
5850a96aa3bSJed Brown   p4est_topidx_t    t, flt, llt;
5860a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
5870a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
5880a96aa3bSJed Brown   PetscInt          maxlevelloc = 0;
5890a96aa3bSJed Brown   p4est_t           *p4est;
5900a96aa3bSJed Brown 
5910a96aa3bSJed Brown   PetscFunctionBegin;
59228b400f6SJacob Faibussowitsch   PetscCheck(pforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing DM_Forest_pforest");
59328b400f6SJacob Faibussowitsch   PetscCheck(pforest->forest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing p4est_t");
5940a96aa3bSJed Brown   p4est = pforest->forest;
5950a96aa3bSJed Brown   flt   = p4est->first_local_tree;
5960a96aa3bSJed Brown   llt   = p4est->last_local_tree;
5970a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
5980a96aa3bSJed Brown     p4est_tree_t *tree  = &(((p4est_tree_t*) p4est->trees->array)[t]);
5990a96aa3bSJed Brown     maxlevelloc = PetscMax((PetscInt)tree->maxlevel,maxlevelloc);
6000a96aa3bSJed Brown   }
6011c2dc1cbSBarry Smith   PetscCall(MPIU_Allreduce(&maxlevelloc,lev,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
6020a96aa3bSJed Brown   PetscFunctionReturn(0);
6030a96aa3bSJed Brown }
6040a96aa3bSJed Brown 
6050a96aa3bSJed Brown /* Puts identity in coarseToFine */
6060a96aa3bSJed Brown /* assumes a matching partition */
6070a96aa3bSJed Brown static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine)
6080a96aa3bSJed Brown {
6090a96aa3bSJed Brown   p4est_topidx_t flt, llt;
6100a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
6110a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
6120a96aa3bSJed Brown   PetscInt       *fromLeaves = NULL, *toLeaves = NULL;
6130a96aa3bSJed Brown   PetscSFNode    *fromRoots  = NULL, *toRoots = NULL;
6140a96aa3bSJed Brown 
6150a96aa3bSJed Brown   PetscFunctionBegin;
6160a96aa3bSJed Brown   flt  = p4estFrom->first_local_tree;
6170a96aa3bSJed Brown   llt  = p4estFrom->last_local_tree;
6189566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm,&fromCoarse));
6190a96aa3bSJed Brown   if (toCoarseFromFine) {
6209566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm,&toCoarse));
6210a96aa3bSJed Brown   }
6220a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
6230a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
6249566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,NULL,NULL,&numLeavesFrom,NULL,NULL));
6259566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo,&toLeaves));
6269566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numLeavesTo,&fromRoots));
6270a96aa3bSJed Brown   if (toCoarseFromFine) {
6289566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom,&fromLeaves));
6299566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(numLeavesFrom,&fromRoots));
6300a96aa3bSJed Brown   }
6319566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,toLeaves,fromRoots,&numLeavesFrom,fromLeaves,toRoots));
6320a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
6339566063dSJacob Faibussowitsch     PetscCall(PetscFree(toLeaves));
6349566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,NULL,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER));
6350a96aa3bSJed Brown   } else { /* generic */
6369566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,toLeaves,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER));
6370a96aa3bSJed Brown   }
6380a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
6390a96aa3bSJed Brown   if (toCoarseFromFine) {
6409566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(toCoarse,numRootsTo,numLeavesFrom,fromLeaves,PETSC_OWN_POINTER,toRoots,PETSC_OWN_POINTER));
6410a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
6420a96aa3bSJed Brown   }
6430a96aa3bSJed Brown   PetscFunctionReturn(0);
6440a96aa3bSJed Brown }
6450a96aa3bSJed Brown 
6460a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
6470a96aa3bSJed Brown static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB)
6480a96aa3bSJed Brown {
6490a96aa3bSJed Brown   p4est_quadrant_t * myCoarseStart = &(p4estA->global_first_position[rank]);
6500a96aa3bSJed Brown   p4est_quadrant_t * myCoarseEnd   = &(p4estA->global_first_position[rank+1]);
6510a96aa3bSJed Brown   p4est_quadrant_t * globalFirstB  = p4estB->global_first_position;
6520a96aa3bSJed Brown 
6530a96aa3bSJed Brown   PetscFunctionBegin;
6540a96aa3bSJed Brown   *startB = -1;
6550a96aa3bSJed Brown   *endB   = -1;
6560a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
6570a96aa3bSJed Brown     PetscInt lo, hi, guess;
6580a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
6590a96aa3bSJed Brown     lo    = 0;
6600a96aa3bSJed Brown     hi    = size;
6610a96aa3bSJed Brown     guess = rank;
6620a96aa3bSJed Brown     while (1) {
6630a96aa3bSJed Brown       int startCompMy, myCompEnd;
6640a96aa3bSJed Brown 
6650a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseStart));
6660a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseStart,&globalFirstB[guess+1]));
6670a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
6680a96aa3bSJed Brown         *startB = guess;
6690a96aa3bSJed Brown         break;
6700a96aa3bSJed Brown       } else if (startCompMy > 0) {  /* guess is to high */
6710a96aa3bSJed Brown         hi = guess;
6720a96aa3bSJed Brown       } else { /* guess is to low */
6730a96aa3bSJed Brown         lo = guess + 1;
6740a96aa3bSJed Brown       }
6750a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6760a96aa3bSJed Brown     }
6770a96aa3bSJed Brown     /* reset bounds, but not guess */
6780a96aa3bSJed Brown     lo = 0;
6790a96aa3bSJed Brown     hi = size;
6800a96aa3bSJed Brown     while (1) {
6810a96aa3bSJed Brown       int startCompMy, myCompEnd;
6820a96aa3bSJed Brown 
6830a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseEnd));
6840a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseEnd,&globalFirstB[guess+1]));
6850a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
6860a96aa3bSJed Brown         *endB = guess + 1;
6870a96aa3bSJed Brown         break;
6880a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
6890a96aa3bSJed Brown         hi = guess;
6900a96aa3bSJed Brown       } else { /* guess is to low */
6910a96aa3bSJed Brown         lo = guess + 1;
6920a96aa3bSJed Brown       }
6930a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
6940a96aa3bSJed Brown     }
6950a96aa3bSJed Brown   }
6960a96aa3bSJed Brown   PetscFunctionReturn(0);
6970a96aa3bSJed Brown }
6980a96aa3bSJed Brown 
6990a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM,DM*);
7000a96aa3bSJed Brown 
7010a96aa3bSJed Brown #define DMSetUp_pforest _append_pforest(DMSetUp)
7020a96aa3bSJed Brown static PetscErrorCode DMSetUp_pforest(DM dm)
7030a96aa3bSJed Brown {
7040a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
7050a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
7060a96aa3bSJed Brown   DM                base, adaptFrom;
7070a96aa3bSJed Brown   DMForestTopology  topoName;
7080a96aa3bSJed Brown   PetscSF           preCoarseToFine = NULL, coarseToPreFine = NULL;
7090a96aa3bSJed Brown   PforestAdaptCtx   ctx;
7100a96aa3bSJed Brown 
7110a96aa3bSJed Brown   PetscFunctionBegin;
7120a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
7130a96aa3bSJed Brown   ctx.maxLevel  = 0;
7140a96aa3bSJed Brown   ctx.currLevel = 0;
7150a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
7160a96aa3bSJed Brown   /* sanity check */
7179566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm,&adaptFrom));
7189566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
7199566063dSJacob Faibussowitsch   PetscCall(DMForestGetTopology(dm,&topoName));
7201dca8a05SBarry Smith   PetscCheck(adaptFrom || base || topoName,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"A forest needs a topology, a base DM, or a DM to adapt from");
7210a96aa3bSJed Brown 
7220a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
7230a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
7240a96aa3bSJed Brown     PetscBool         ispforest;
7250a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
7260a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
7270a96aa3bSJed Brown 
7289566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)adaptFrom,DMPFOREST,&ispforest));
72928b400f6SJacob Faibussowitsch     PetscCheck(ispforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Trying to adapt from %s, which is not %s",((PetscObject)adaptFrom)->type_name,DMPFOREST);
73028b400f6SJacob Faibussowitsch     PetscCheck(apforest->topo,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"The pre-adaptation forest must have a topology");
7319566063dSJacob Faibussowitsch     PetscCall(DMSetUp(adaptFrom));
7329566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm,&base));
7339566063dSJacob Faibussowitsch     PetscCall(DMForestGetTopology(dm,&topoName));
7340a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
7350a96aa3bSJed Brown     PetscBool isPlex, isDA;
7360a96aa3bSJed Brown 
7379566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject)base,&topoName));
7389566063dSJacob Faibussowitsch     PetscCall(DMForestSetTopology(dm,topoName));
7399566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base,DMPLEX,&isPlex));
7409566063dSJacob Faibussowitsch     PetscCall(PetscObjectTypeCompare((PetscObject)base,DMDA,&isDA));
7410a96aa3bSJed Brown     if (isPlex) {
7420a96aa3bSJed Brown       MPI_Comm             comm = PetscObjectComm((PetscObject)dm);
7430a96aa3bSJed Brown       PetscInt             depth;
7440a96aa3bSJed Brown       PetscMPIInt          size;
7450a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
7460a96aa3bSJed Brown       DMFTopology_pforest  *topo;
7470a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
7480a96aa3bSJed Brown 
7499566063dSJacob Faibussowitsch       PetscCall(DMPlexGetDepth(base,&depth));
7500a96aa3bSJed Brown       if (depth == 1) {
7510a96aa3bSJed Brown         DM connDM;
7520a96aa3bSJed Brown 
7539566063dSJacob Faibussowitsch         PetscCall(DMPlexInterpolate(base,&connDM));
7540a96aa3bSJed Brown         base = connDM;
7559566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm,base));
7569566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&connDM));
75763a3b9bcSJacob Faibussowitsch       } else PetscCheck(depth == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Base plex is neither interpolated nor uninterpolated? depth %" PetscInt_FMT ", expected 2 or %d",depth,P4EST_DIM + 1);
7589566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Comm_size(comm,&size));
7590a96aa3bSJed Brown       if (size > 1) {
7600a96aa3bSJed Brown         DM      dmRedundant;
7610a96aa3bSJed Brown         PetscSF sf;
7620a96aa3bSJed Brown 
7639566063dSJacob Faibussowitsch         PetscCall(DMPlexGetRedundantDM(base,&sf,&dmRedundant));
76428b400f6SJacob Faibussowitsch         PetscCheck(dmRedundant,comm,PETSC_ERR_PLIB,"Could not create redundant DM");
7659566063dSJacob Faibussowitsch         PetscCall(PetscObjectCompose((PetscObject)dmRedundant,"_base_migration_sf",(PetscObject)sf));
7669566063dSJacob Faibussowitsch         PetscCall(PetscSFDestroy(&sf));
7670a96aa3bSJed Brown         base = dmRedundant;
7689566063dSJacob Faibussowitsch         PetscCall(DMForestSetBaseDM(dm,base));
7699566063dSJacob Faibussowitsch         PetscCall(DMDestroy(&dmRedundant));
7700a96aa3bSJed Brown       }
7719566063dSJacob Faibussowitsch       PetscCall(DMViewFromOptions(base,NULL,"-dm_p4est_base_view"));
7729566063dSJacob Faibussowitsch       PetscCall(DMPlexCreateConnectivity_pforest(base,&conn,&tree_face_to_uniq));
7739566063dSJacob Faibussowitsch       PetscCall(PetscNewLog(dm,&topo));
7740a96aa3bSJed Brown       topo->refct = 1;
7750a96aa3bSJed Brown       topo->conn  = conn;
7760a96aa3bSJed Brown       topo->geom  = NULL;
7770a96aa3bSJed Brown       {
7780a96aa3bSJed Brown         PetscErrorCode (*map)(DM,PetscInt,PetscInt,const PetscReal[],PetscReal[],void*);
7790a96aa3bSJed Brown         void           *mapCtx;
7800a96aa3bSJed Brown 
7819566063dSJacob Faibussowitsch         PetscCall(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx));
7820a96aa3bSJed Brown         if (map) {
7830a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
7840a96aa3bSJed Brown           p4est_geometry_t           *geom;
7850a96aa3bSJed Brown 
7869566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom_pforest));
7879566063dSJacob Faibussowitsch           PetscCall(DMGetCoordinateDim(dm,&geom_pforest->coordDim));
7880a96aa3bSJed Brown           geom_pforest->map    = map;
7890a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
7900a96aa3bSJed Brown           PetscStackCallP4estReturn(geom_pforest->inner,p4est_geometry_new_connectivity,(conn));
7919566063dSJacob Faibussowitsch           PetscCall(PetscNew(&geom));
7920a96aa3bSJed Brown           geom->name    = topoName;
7930a96aa3bSJed Brown           geom->user    = geom_pforest;
7940a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
7950a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
7960a96aa3bSJed Brown           topo->geom    = geom;
7970a96aa3bSJed Brown         }
7980a96aa3bSJed Brown       }
7990a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
8000a96aa3bSJed Brown       pforest->topo           = topo;
80128b400f6SJacob Faibussowitsch     } else PetscCheck(!isDA,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Not implemented yet");
8020a96aa3bSJed Brown #if 0
8030a96aa3bSJed Brown       PetscInt N[3], P[3];
8040a96aa3bSJed Brown 
8050a96aa3bSJed Brown       /* get the sizes, periodicities */
8060a96aa3bSJed Brown       /* ... */
8070a96aa3bSJed Brown                                                                   /* don't use Morton order */
8089566063dSJacob Faibussowitsch       PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE));
8090a96aa3bSJed Brown #endif
8100a96aa3bSJed Brown     {
8110a96aa3bSJed Brown       PetscInt numLabels, l;
8120a96aa3bSJed Brown 
8139566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(base,&numLabels));
8140a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
8150a96aa3bSJed Brown         PetscBool  isDepth, isGhost, isVTK, isDim, isCellType;
8160a96aa3bSJed Brown         DMLabel    label, labelNew;
8170a96aa3bSJed Brown         PetscInt   defVal;
8180a96aa3bSJed Brown         const char *name;
8190a96aa3bSJed Brown 
8209566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(base, l, &name));
8219566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(base, l, &label));
8229566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"depth",&isDepth));
8230a96aa3bSJed Brown         if (isDepth) continue;
8249566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"dim",&isDim));
8250a96aa3bSJed Brown         if (isDim) continue;
8269566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"celltype",&isCellType));
8270a96aa3bSJed Brown         if (isCellType) continue;
8289566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"ghost",&isGhost));
8290a96aa3bSJed Brown         if (isGhost) continue;
8309566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"vtk",&isVTK));
8310a96aa3bSJed Brown         if (isVTK) continue;
8329566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,name));
8339566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm,name,&labelNew));
8349566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label,&defVal));
8359566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew,defVal));
8360a96aa3bSJed Brown       }
8370a96aa3bSJed Brown       /* map dm points (internal plex) to base
8380a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
8390a96aa3bSJed Brown          and propagating back to the coarsest
8400a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
8410a96aa3bSJed Brown          during DMForestTransferVecFromBase */
8429566063dSJacob Faibussowitsch       PetscCall(DMForestGetMinimumRefinement(dm,&l));
8430a96aa3bSJed Brown       if (!l) {
8449566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,"_forest_base_subpoint_map"));
8450a96aa3bSJed Brown       }
8460a96aa3bSJed Brown     }
8470a96aa3bSJed Brown   } else { /* construct from topology name */
8480a96aa3bSJed Brown     DMFTopology_pforest *topo;
8490a96aa3bSJed Brown 
8509566063dSJacob Faibussowitsch     PetscCall(DMFTopologyCreate_pforest(dm,topoName,&topo));
8510a96aa3bSJed Brown     pforest->topo = topo;
8520a96aa3bSJed Brown     /* TODO: construct base? */
8530a96aa3bSJed Brown   }
8540a96aa3bSJed Brown 
8550a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
8560a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
8570a96aa3bSJed Brown     DMLabel           adaptLabel;
8580a96aa3bSJed Brown     PetscInt          defaultValue;
8590a96aa3bSJed Brown     PetscInt          numValues, numValuesGlobal, cLocalStart, count;
8600a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
8610a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
8620a96aa3bSJed Brown     PetscBool         computeAdaptSF;
8630a96aa3bSJed Brown     p4est_topidx_t    flt, llt, t;
8640a96aa3bSJed Brown 
8650a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
8660a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
8670a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
8689566063dSJacob Faibussowitsch     PetscCall(DMForestGetComputeAdaptivitySF(dm,&computeAdaptSF));
8690a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_copy,(apforest->forest, 0)); /* 0 indicates no data copying */
8709566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm,&adaptLabel));
8710a96aa3bSJed Brown     if (adaptLabel) {
8720a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
8739566063dSJacob Faibussowitsch       PetscCall(DMLabelGetNumValues(adaptLabel,&numValues));
8749566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Allreduce(&numValues,&numValuesGlobal,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)adaptFrom)));
8759566063dSJacob Faibussowitsch       PetscCall(DMLabelGetDefaultValue(adaptLabel,&defaultValue));
8760a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
8779566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
8789566063dSJacob Faibussowitsch         PetscCall(DMPforestGetRefinementLevel(dm,&ctx.currLevel));
8790a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8800a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_currlevel,NULL));
8810a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8820a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8830a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
8840a96aa3bSJed Brown         if (computeAdaptSF) {
8859566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL));
8860a96aa3bSJed Brown         }
8870a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */
8889566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
8890a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
8900a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_uniform,NULL));
8910a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
8920a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
8930a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
8940a96aa3bSJed Brown         if (computeAdaptSF) {
8959566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL));
8960a96aa3bSJed Brown         }
8970a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
8989566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&ctx.maxLevel));
8990a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
9000a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_uniform,NULL));
9010a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
9020a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
9030a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
9040a96aa3bSJed Brown         if (computeAdaptSF) {
9059566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,NULL));
9060a96aa3bSJed Brown         }
9070a96aa3bSJed Brown       } else if (numValuesGlobal) {
9080a96aa3bSJed Brown         p4est_t                    *p4est = pforest->forest;
9090a96aa3bSJed Brown         PetscInt                   *cellFlags;
9100a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
9110a96aa3bSJed Brown         PetscSF                    cellSF;
9120a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
9130a96aa3bSJed Brown         PetscBool                  adaptAny;
9140a96aa3bSJed Brown 
9159566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&ctx.maxLevel));
9169566063dSJacob Faibussowitsch         PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel));
9179566063dSJacob Faibussowitsch         PetscCall(DMForestGetAdaptivityStrategy(dm,&strategy));
9189566063dSJacob Faibussowitsch         PetscCall(PetscStrncmp(strategy,"any",3,&adaptAny));
9199566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellChart(adaptFrom,&cStart,&cEnd));
9209566063dSJacob Faibussowitsch         PetscCall(DMForestGetCellSF(adaptFrom,&cellSF));
9219566063dSJacob Faibussowitsch         PetscCall(PetscMalloc1(cEnd-cStart,&cellFlags));
9229566063dSJacob Faibussowitsch         for (c = cStart; c < cEnd; c++) PetscCall(DMLabelGetValue(adaptLabel,c,&cellFlags[c-cStart]));
9230a96aa3bSJed Brown         if (cellSF) {
9240a96aa3bSJed Brown           if (adaptAny) {
9259566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX));
9269566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX));
9270a96aa3bSJed Brown           } else {
9289566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN));
9299566063dSJacob Faibussowitsch             PetscCall(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN));
9300a96aa3bSJed Brown           }
9310a96aa3bSJed Brown         }
9320a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
9330a96aa3bSJed Brown           p4est_tree_t       *tree    = &(((p4est_tree_t*) p4est->trees->array)[t]);
9340a96aa3bSJed Brown           PetscInt           numQuads = (PetscInt) tree->quadrants.elem_count, i;
9350a96aa3bSJed Brown           p4est_quadrant_t   *quads   = (p4est_quadrant_t *) tree->quadrants.array;
9360a96aa3bSJed Brown 
9370a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9380a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
9390a96aa3bSJed Brown             q->p.user_int = cellFlags[count++];
9400a96aa3bSJed Brown           }
9410a96aa3bSJed Brown         }
9429566063dSJacob Faibussowitsch         PetscCall(PetscFree(cellFlags));
9430a96aa3bSJed Brown 
9440a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
9450a96aa3bSJed Brown         if (adaptAny) {
9460a96aa3bSJed Brown           PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_any,pforest_init_determine));
9470a96aa3bSJed Brown         } else {
9480a96aa3bSJed Brown           PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_all,pforest_init_determine));
9490a96aa3bSJed Brown         }
9500a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_flag,NULL));
9510a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
9520a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
9530a96aa3bSJed Brown         if (computeAdaptSF) {
9549566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,&coarseToPreFine));
9550a96aa3bSJed Brown         }
9560a96aa3bSJed Brown       }
9570a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
9580a96aa3bSJed Brown         p4est_tree_t       *atree    = &(((p4est_tree_t*) apforest->forest->trees->array)[t]);
9590a96aa3bSJed Brown         p4est_tree_t       *tree     = &(((p4est_tree_t*) pforest->forest->trees->array)[t]);
9600a96aa3bSJed Brown         PetscInt           anumQuads = (PetscInt) atree->quadrants.elem_count, i;
9610a96aa3bSJed Brown         PetscInt           numQuads  = (PetscInt) tree->quadrants.elem_count;
9620a96aa3bSJed Brown         p4est_quadrant_t   *aquads   = (p4est_quadrant_t *) atree->quadrants.array;
9630a96aa3bSJed Brown         p4est_quadrant_t   *quads    = (p4est_quadrant_t *) tree->quadrants.array;
9640a96aa3bSJed Brown 
9650a96aa3bSJed Brown         if (anumQuads != numQuads) {
9660a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
9670a96aa3bSJed Brown         } else {
9680a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
9690a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
9700a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
9710a96aa3bSJed Brown 
9720a96aa3bSJed Brown             if (aq->level != q->level) {
9730a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
9740a96aa3bSJed Brown               break;
9750a96aa3bSJed Brown             }
9760a96aa3bSJed Brown           }
9770a96aa3bSJed Brown         }
9780a96aa3bSJed Brown         if (ctx.anyChange) {
9790a96aa3bSJed Brown           break;
9800a96aa3bSJed Brown         }
9810a96aa3bSJed Brown       }
9820a96aa3bSJed Brown     }
9830a96aa3bSJed Brown     {
9840a96aa3bSJed Brown       PetscInt numLabels, l;
9850a96aa3bSJed Brown 
9869566063dSJacob Faibussowitsch       PetscCall(DMGetNumLabels(adaptFrom,&numLabels));
9870a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
9880a96aa3bSJed Brown         PetscBool  isDepth, isCellType, isGhost, isVTK;
9890a96aa3bSJed Brown         DMLabel    label, labelNew;
9900a96aa3bSJed Brown         PetscInt   defVal;
9910a96aa3bSJed Brown         const char *name;
9920a96aa3bSJed Brown 
9939566063dSJacob Faibussowitsch         PetscCall(DMGetLabelName(adaptFrom, l, &name));
9949566063dSJacob Faibussowitsch         PetscCall(DMGetLabelByNum(adaptFrom, l, &label));
9959566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"depth",&isDepth));
9960a96aa3bSJed Brown         if (isDepth) continue;
9979566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"celltype",&isCellType));
9980a96aa3bSJed Brown         if (isCellType) continue;
9999566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"ghost",&isGhost));
10000a96aa3bSJed Brown         if (isGhost) continue;
10019566063dSJacob Faibussowitsch         PetscCall(PetscStrcmp(name,"vtk",&isVTK));
10020a96aa3bSJed Brown         if (isVTK) continue;
10039566063dSJacob Faibussowitsch         PetscCall(DMCreateLabel(dm,name));
10049566063dSJacob Faibussowitsch         PetscCall(DMGetLabel(dm,name,&labelNew));
10059566063dSJacob Faibussowitsch         PetscCall(DMLabelGetDefaultValue(label,&defVal));
10069566063dSJacob Faibussowitsch         PetscCall(DMLabelSetDefaultValue(labelNew,defVal));
10070a96aa3bSJed Brown       }
10080a96aa3bSJed Brown     }
10090a96aa3bSJed Brown   } else { /* initial */
10100a96aa3bSJed Brown     PetscInt initLevel, minLevel;
10110a96aa3bSJed Brown 
10129566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm,&initLevel));
10139566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
10140a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_new_ext,(PetscObjectComm((PetscObject)dm),pforest->topo->conn,
10150a96aa3bSJed Brown                                                              0,           /* minimum number of quadrants per processor */
10160a96aa3bSJed Brown                                                              initLevel,   /* level of refinement */
10170a96aa3bSJed Brown                                                              1,           /* uniform refinement */
10180a96aa3bSJed Brown                                                              0,           /* we don't allocate any per quadrant data */
10190a96aa3bSJed Brown                                                              NULL,        /* there is no special quadrant initialization */
10200a96aa3bSJed Brown                                                              (void*)dm)); /* this dm is the user context */
10210a96aa3bSJed Brown 
10220a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10230a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
10240a96aa3bSJed Brown       PetscBool  flgPattern, flgFractal;
10250a96aa3bSJed Brown       PetscInt   corner = 0;
10260a96aa3bSJed Brown       PetscInt   corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
10270a96aa3bSJed Brown       PetscReal  likelihood = 1./ P4EST_DIM;
10280a96aa3bSJed Brown       PetscInt   pattern;
10290a96aa3bSJed Brown       const char *prefix;
10300a96aa3bSJed Brown 
10319566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
10329566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetEList(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_pattern",DMRefinePatternName,PATTERN_COUNT,&pattern,&flgPattern));
10339566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_corner",&corner,NULL));
10349566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_fractal_corners",corners,&ncorner,&flgFractal));
10359566063dSJacob Faibussowitsch       PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_hash_likelihood",&likelihood,NULL));
10360a96aa3bSJed Brown 
10370a96aa3bSJed Brown       if (flgPattern) {
10380a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
10390a96aa3bSJed Brown         PetscInt           maxLevel;
10400a96aa3bSJed Brown 
10419566063dSJacob Faibussowitsch         PetscCall(DMForestGetMaximumRefinement(dm,&maxLevel));
10429566063dSJacob Faibussowitsch         PetscCall(PetscNewLog(dm,&ctx));
10430a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel,P4EST_QMAXLEVEL);
10440a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
10450a96aa3bSJed Brown         switch (pattern) {
10460a96aa3bSJed Brown         case PATTERN_HASH:
10470a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
10480a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
10490a96aa3bSJed Brown           break;
10500a96aa3bSJed Brown         case PATTERN_CORNER:
10510a96aa3bSJed Brown           ctx->corner    = corner;
10520a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
10530a96aa3bSJed Brown           break;
10540a96aa3bSJed Brown         case PATTERN_CENTER:
10550a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Center;
10560a96aa3bSJed Brown           break;
10570a96aa3bSJed Brown         case PATTERN_FRACTAL:
10580a96aa3bSJed Brown           if (flgFractal) {
10590a96aa3bSJed Brown             PetscInt i;
10600a96aa3bSJed Brown 
10610a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
10620a96aa3bSJed Brown           } else {
10630a96aa3bSJed Brown #if !defined(P4_TO_P8)
10640a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
10650a96aa3bSJed Brown #else
10660a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
10670a96aa3bSJed Brown #endif
10680a96aa3bSJed Brown           }
10690a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
10700a96aa3bSJed Brown           break;
10710a96aa3bSJed Brown         default:
10720a96aa3bSJed Brown           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Not a valid refinement pattern");
10730a96aa3bSJed Brown         }
10740a96aa3bSJed Brown 
10750a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) ctx;
10760a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,1,ctx->refine_fn,NULL));
10770a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
10789566063dSJacob Faibussowitsch         PetscCall(PetscFree(ctx));
10790a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
10800a96aa3bSJed Brown       }
10810a96aa3bSJed Brown     }
10820a96aa3bSJed Brown   }
10830a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
10840a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
10850a96aa3bSJed Brown 
10869566063dSJacob Faibussowitsch     PetscCall(DMPforestGetRefinementLevel(dm,&currLevel));
10879566063dSJacob Faibussowitsch     PetscCall(DMForestGetInitialRefinement(dm,&initLevel));
10889566063dSJacob Faibussowitsch     PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
10890a96aa3bSJed Brown     if (currLevel > minLevel) {
10900a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
10910a96aa3bSJed Brown       DMLabel           coarsen;
10920a96aa3bSJed Brown       DM                coarseDM;
10930a96aa3bSJed Brown 
10949566063dSJacob Faibussowitsch       PetscCall(DMForestTemplate(dm,MPI_COMM_NULL,&coarseDM));
10959566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityPurpose(coarseDM,DM_ADAPT_COARSEN));
10969566063dSJacob Faibussowitsch       PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen",&coarsen));
10979566063dSJacob Faibussowitsch       PetscCall(DMLabelSetDefaultValue(coarsen,DM_ADAPT_COARSEN));
10989566063dSJacob Faibussowitsch       PetscCall(DMForestSetAdaptivityLabel(coarseDM,coarsen));
10999566063dSJacob Faibussowitsch       PetscCall(DMLabelDestroy(&coarsen));
11009566063dSJacob Faibussowitsch       PetscCall(DMSetCoarseDM(dm,coarseDM));
11019566063dSJacob Faibussowitsch       PetscCall(PetscObjectDereference((PetscObject)coarseDM));
11020a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
11039566063dSJacob Faibussowitsch       PetscCall(DMForestSetInitialRefinement(coarseDM,initLevel));
11049566063dSJacob Faibussowitsch       PetscCall(DMForestSetMinimumRefinement(coarseDM,minLevel));
11050a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest*) ((DM_Forest*) coarseDM->data)->data;
11060a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
11070a96aa3bSJed Brown     }
11080a96aa3bSJed Brown   }
11090a96aa3bSJed Brown 
11100a96aa3bSJed Brown   { /* repartitioning and overlap */
11110a96aa3bSJed Brown     PetscMPIInt size, rank;
11120a96aa3bSJed Brown 
11139566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size));
11149566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
11150a96aa3bSJed Brown     if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
11160a96aa3bSJed Brown       PetscBool      copyForest   = PETSC_FALSE;
11170a96aa3bSJed Brown       p4est_t        *forest_copy = NULL;
11180a96aa3bSJed Brown       p4est_gloidx_t shipped      = 0;
11190a96aa3bSJed Brown 
11200a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
11210a96aa3bSJed Brown       if (copyForest) PetscStackCallP4estReturn(forest_copy,p4est_copy,(pforest->forest,0));
11220a96aa3bSJed Brown 
11230a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
11240a96aa3bSJed Brown         PetscStackCallP4estReturn(shipped,p4est_partition_ext,(pforest->forest,(int)pforest->partition_for_coarsening,NULL));
11250a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Non-uniform partition cases not implemented yet");
11260a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
11270a96aa3bSJed Brown       if (forest_copy) {
11280a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
11290a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
11300a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
11310a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
11320a96aa3bSJed Brown           PetscSFNode    *repartRoots;
11330a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
11340a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank+1];
11350a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
11360a96aa3bSJed Brown 
11370a96aa3bSJed Brown           numRoots  = (PetscInt) (forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
11380a96aa3bSJed Brown           numLeaves = (PetscInt) (postEnd - postStart);
11399566063dSJacob Faibussowitsch           PetscCall(DMPforestComputeOverlappingRanks(size,rank,pforest->forest,forest_copy,&pStart,&pEnd));
11409566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1((PetscInt) pforest->forest->local_num_quadrants,&repartRoots));
11410a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
11420a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
11430a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p+1];
11440a96aa3bSJed Brown             PetscInt       q;
11450a96aa3bSJed Brown 
11460a96aa3bSJed Brown             if (preEnd == preStart) continue;
114708401ef6SPierre Jolivet             PetscCheck(preStart <= postStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Bad partition overlap computation");
11480a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
11490a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
11500a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
11510a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
11520a96aa3bSJed Brown             }
11530a96aa3bSJed Brown             partOffset = preEnd;
11540a96aa3bSJed Brown           }
11559566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&repartSF));
11569566063dSJacob Faibussowitsch           PetscCall(PetscSFSetGraph(repartSF,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,repartRoots,PETSC_OWN_POINTER));
11579566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(repartSF));
11580a96aa3bSJed Brown           if (preCoarseToFine) {
11590a96aa3bSJed Brown             PetscSF        repartSFembed, preCoarseToFineNew;
11600a96aa3bSJed Brown             PetscInt       nleaves;
11610a96aa3bSJed Brown             const PetscInt *leaves;
11620a96aa3bSJed Brown 
11639566063dSJacob Faibussowitsch             PetscCall(PetscSFSetUp(preCoarseToFine));
11649566063dSJacob Faibussowitsch             PetscCall(PetscSFGetGraph(preCoarseToFine,NULL,&nleaves,&leaves,NULL));
11650a96aa3bSJed Brown             if (leaves) {
11669566063dSJacob Faibussowitsch               PetscCall(PetscSFCreateEmbeddedRootSF(repartSF,nleaves,leaves,&repartSFembed));
11670a96aa3bSJed Brown             } else {
11680a96aa3bSJed Brown               repartSFembed = repartSF;
11699566063dSJacob Faibussowitsch               PetscCall(PetscObjectReference((PetscObject)repartSFembed));
11700a96aa3bSJed Brown             }
11719566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(preCoarseToFine,repartSFembed,&preCoarseToFineNew));
11729566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&preCoarseToFine));
11739566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFembed));
11740a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
11750a96aa3bSJed Brown           }
11760a96aa3bSJed Brown           if (coarseToPreFine) {
11770a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
11780a96aa3bSJed Brown 
11799566063dSJacob Faibussowitsch             PetscCall(PetscSFCreateInverseSF(repartSF,&repartSFinv));
11809566063dSJacob Faibussowitsch             PetscCall(PetscSFCompose(repartSFinv,coarseToPreFine,&coarseToPreFineNew));
11819566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&coarseToPreFine));
11829566063dSJacob Faibussowitsch             PetscCall(PetscSFDestroy(&repartSFinv));
11830a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
11840a96aa3bSJed Brown           }
11859566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&repartSF));
11860a96aa3bSJed Brown         }
11870a96aa3bSJed Brown         PetscStackCallP4est(p4est_destroy,(forest_copy));
11880a96aa3bSJed Brown       }
11890a96aa3bSJed Brown     }
11900a96aa3bSJed Brown     if (size > 1) {
11910a96aa3bSJed Brown       PetscInt overlap;
11920a96aa3bSJed Brown 
11939566063dSJacob Faibussowitsch       PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
11940a96aa3bSJed Brown 
11950a96aa3bSJed Brown       if (adaptFrom) {
11960a96aa3bSJed Brown         PetscInt aoverlap;
11970a96aa3bSJed Brown 
11989566063dSJacob Faibussowitsch         PetscCall(DMForestGetPartitionOverlap(adaptFrom,&aoverlap));
11990a96aa3bSJed Brown         if (aoverlap != overlap) {
12000a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
12010a96aa3bSJed Brown         }
12020a96aa3bSJed Brown       }
12030a96aa3bSJed Brown 
12040a96aa3bSJed Brown       if (overlap > 0) {
12050a96aa3bSJed Brown         PetscInt i, cLocalStart;
12060a96aa3bSJed Brown         PetscInt cEnd;
12070a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
12080a96aa3bSJed Brown 
12090a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->ghost,p4est_ghost_new,(pforest->forest,P4EST_CONNECT_FULL));
12100a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->lnodes,p4est_lnodes_new,(pforest->forest,pforest->ghost,-P4EST_DIM));
12110a96aa3bSJed Brown         PetscStackCallP4est(p4est_ghost_support_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
12120a96aa3bSJed Brown         for (i = 1; i < overlap; i++) PetscStackCallP4est(p4est_ghost_expand_by_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
12130a96aa3bSJed Brown 
12140a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
12150a96aa3bSJed Brown         cEnd        = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
12160a96aa3bSJed Brown 
12170a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
12180a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
12199566063dSJacob Faibussowitsch           if (adaptFrom) PetscCall(DMForestGetCellSF(adaptFrom,&preCellSF));
12200a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
12219566063dSJacob Faibussowitsch           PetscCall(DMForestGetCellSF(dm,&cellSF));
12220a96aa3bSJed Brown         }
12230a96aa3bSJed Brown         if (preCoarseToFine) {
12240a96aa3bSJed Brown           PetscSF           preCoarseToFineNew;
12250a96aa3bSJed Brown           PetscInt          nleaves, nroots, *leavesNew, i, nleavesNew;
12260a96aa3bSJed Brown           const PetscInt    *leaves;
12270a96aa3bSJed Brown           const PetscSFNode *remotes;
12280a96aa3bSJed Brown           PetscSFNode       *remotesAll;
12290a96aa3bSJed Brown 
12309566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(preCoarseToFine));
12319566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCoarseToFine,&nroots,&nleaves,&leaves,&remotes));
12329566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(cEnd,&remotesAll));
12330a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
12340a96aa3bSJed Brown             remotesAll[i].rank  = -1;
12350a96aa3bSJed Brown             remotesAll[i].index = -1;
12360a96aa3bSJed Brown           }
12370a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
12389566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(cellSF));
12399566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE));
12409566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE));
12410a96aa3bSJed Brown           nleavesNew = 0;
12420a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12430a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
12440a96aa3bSJed Brown           }
12459566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesNew,&leavesNew));
12460a96aa3bSJed Brown           nleavesNew = 0;
12470a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
12480a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
12490a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
12500a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
12510a96aa3bSJed Brown               nleavesNew++;
12520a96aa3bSJed Brown             }
12530a96aa3bSJed Brown           }
12549566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&preCoarseToFineNew));
12550a96aa3bSJed Brown           if (nleavesNew < cEnd) {
12569566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,leavesNew,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES));
12570a96aa3bSJed Brown           } else { /* all cells are leaves */
12589566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
12599566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,NULL,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES));
12600a96aa3bSJed Brown           }
12619566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesAll));
12629566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&preCoarseToFine));
12630a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12640a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
12650a96aa3bSJed Brown         }
12660a96aa3bSJed Brown         if (coarseToPreFine) {
12670a96aa3bSJed Brown           PetscSF           coarseToPreFineNew;
12680a96aa3bSJed Brown           PetscInt          nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
12690a96aa3bSJed Brown           const PetscInt    *leaves;
12700a96aa3bSJed Brown           const PetscSFNode *remotes;
12710a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
12720a96aa3bSJed Brown 
12739566063dSJacob Faibussowitsch           PetscCall(PetscSFSetUp(coarseToPreFine));
12749566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(coarseToPreFine,&nroots,&nleaves,&leaves,&remotes));
12759566063dSJacob Faibussowitsch           PetscCall(PetscSFGetGraph(preCellSF,NULL,&nleavesCellSF,NULL,NULL));
12769566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nroots,&remotesNewRoot));
12779566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleaves,&remotesNew));
12780a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
12790a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
12800a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
12810a96aa3bSJed Brown           }
12829566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE));
12839566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE));
12849566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNewRoot));
12859566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesCellSF,&remotesExpanded));
12860a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12870a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
12880a96aa3bSJed Brown             remotesExpanded[i].index = -1;
12890a96aa3bSJed Brown           }
12900a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
12919566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesNew));
12929566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastBegin(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE));
12939566063dSJacob Faibussowitsch           PetscCall(PetscSFBcastEnd(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE));
12940a96aa3bSJed Brown 
12950a96aa3bSJed Brown           nleavesExpanded = 0;
12960a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
12970a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
12980a96aa3bSJed Brown           }
12999566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(nleavesExpanded,&leavesNew));
13000a96aa3bSJed Brown           nleavesExpanded = 0;
13010a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
13020a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
13030a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
13040a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
13050a96aa3bSJed Brown               nleavesExpanded++;
13060a96aa3bSJed Brown             }
13070a96aa3bSJed Brown           }
13089566063dSJacob Faibussowitsch           PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&coarseToPreFineNew));
13090a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
13109566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,leavesNew,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES));
13110a96aa3bSJed Brown           } else {
13129566063dSJacob Faibussowitsch             PetscCall(PetscFree(leavesNew));
13139566063dSJacob Faibussowitsch             PetscCall(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,NULL,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES));
13140a96aa3bSJed Brown           }
13159566063dSJacob Faibussowitsch           PetscCall(PetscFree(remotesExpanded));
13169566063dSJacob Faibussowitsch           PetscCall(PetscSFDestroy(&coarseToPreFine));
13170a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
13180a96aa3bSJed Brown         }
13190a96aa3bSJed Brown       }
13200a96aa3bSJed Brown     }
13210a96aa3bSJed Brown   }
13220a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
13230a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
13240a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
13259566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Allreduce(&ctx.anyChange,&(pforest->adaptivitySuccess),1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm)));
13269566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,NULL));
13270a96aa3bSJed Brown   PetscFunctionReturn(0);
13280a96aa3bSJed Brown }
13290a96aa3bSJed Brown 
13300a96aa3bSJed Brown #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
13310a96aa3bSJed Brown static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success)
13320a96aa3bSJed Brown {
13330a96aa3bSJed Brown   DM_Forest         *forest;
13340a96aa3bSJed Brown   DM_Forest_pforest *pforest;
13350a96aa3bSJed Brown 
13360a96aa3bSJed Brown   PetscFunctionBegin;
13370a96aa3bSJed Brown   forest   = (DM_Forest *) dm->data;
13380a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *) forest->data;
13390a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
13400a96aa3bSJed Brown   PetscFunctionReturn(0);
13410a96aa3bSJed Brown }
13420a96aa3bSJed Brown 
13430a96aa3bSJed Brown #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
13440a96aa3bSJed Brown static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer)
13450a96aa3bSJed Brown {
13460a96aa3bSJed Brown   DM             dm = (DM) odm;
13470a96aa3bSJed Brown 
13480a96aa3bSJed Brown   PetscFunctionBegin;
13490a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13500a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13519566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13520a96aa3bSJed Brown   switch (viewer->format) {
13530a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
13540a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO:
13550a96aa3bSJed Brown   {
13560a96aa3bSJed Brown     PetscInt   dim;
13570a96aa3bSJed Brown     const char *name;
13580a96aa3bSJed Brown 
13599566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) dm, &name));
13609566063dSJacob Faibussowitsch     PetscCall(DMGetDimension(dm, &dim));
136163a3b9bcSJacob Faibussowitsch     if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "Forest %s in %" PetscInt_FMT " dimensions:\n", name, dim));
136263a3b9bcSJacob Faibussowitsch     else      PetscCall(PetscViewerASCIIPrintf(viewer, "Forest in %" PetscInt_FMT " dimensions:\n", dim));
13630a96aa3bSJed Brown   }
13640a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
13650a96aa3bSJed Brown   case PETSC_VIEWER_LOAD_BALANCE:
13660a96aa3bSJed Brown   {
13670a96aa3bSJed Brown     DM plex;
13680a96aa3bSJed Brown 
13699566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dm, &plex));
13709566063dSJacob Faibussowitsch     PetscCall(DMView(plex, viewer));
13710a96aa3bSJed Brown   }
13720a96aa3bSJed Brown   break;
137398921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
13740a96aa3bSJed Brown   }
13750a96aa3bSJed Brown   PetscFunctionReturn(0);
13760a96aa3bSJed Brown }
13770a96aa3bSJed Brown 
13780a96aa3bSJed Brown #define DMView_VTK_pforest _append_pforest(DMView_VTK)
13790a96aa3bSJed Brown static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer)
13800a96aa3bSJed Brown {
13810a96aa3bSJed Brown   DM                dm       = (DM) odm;
13820a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
13830a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
13840a96aa3bSJed Brown   PetscBool         isvtk;
13850a96aa3bSJed Brown   PetscReal         vtkScale = 1. - PETSC_MACHINE_EPSILON;
13860a96aa3bSJed Brown   PetscViewer_VTK   *vtk     = (PetscViewer_VTK*)viewer->data;
13870a96aa3bSJed Brown   const char        *name;
13880a96aa3bSJed Brown   char              *filenameStrip = NULL;
13890a96aa3bSJed Brown   PetscBool         hasExt;
13900a96aa3bSJed Brown   size_t            len;
13910a96aa3bSJed Brown   p4est_geometry_t  *geom;
13920a96aa3bSJed Brown 
13930a96aa3bSJed Brown   PetscFunctionBegin;
13940a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
13950a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
13969566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
13970a96aa3bSJed Brown   geom = pforest->topo->geom;
13989566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk));
139928b400f6SJacob Faibussowitsch   PetscCheck(isvtk,PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
14000a96aa3bSJed Brown   switch (viewer->format) {
14010a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
140228b400f6SJacob Faibussowitsch     PetscCheck(pforest->forest,PetscObjectComm(odm),PETSC_ERR_ARG_WRONG,"DM has not been setup with a valid forest");
14030a96aa3bSJed Brown     name = vtk->filename;
14049566063dSJacob Faibussowitsch     PetscCall(PetscStrlen(name,&len));
14059566063dSJacob Faibussowitsch     PetscCall(PetscStrcasecmp(name+len-4,".vtu",&hasExt));
14060a96aa3bSJed Brown     if (hasExt) {
14079566063dSJacob Faibussowitsch       PetscCall(PetscStrallocpy(name,&filenameStrip));
14080a96aa3bSJed Brown       filenameStrip[len-4]='\0';
14090a96aa3bSJed Brown       name                = filenameStrip;
14100a96aa3bSJed Brown     }
14110a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4estReturn(geom,p4est_geometry_new_connectivity,(pforest->topo->conn));
14120a96aa3bSJed Brown     {
14130a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
14140a96aa3bSJed Brown       int                 footerr;
14150a96aa3bSJed Brown 
14160a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_context_new,(pforest->forest,name));
14170a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_geom,(pvtk,geom));
14180a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_scale,(pvtk,(double)vtkScale));
14190a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_header,(pvtk));
142028b400f6SJacob Faibussowitsch       PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_header() failed");
14210a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_cell_dataf,(pvtk,
14220a96aa3bSJed Brown                                                                  1, /* write tree */
14230a96aa3bSJed Brown                                                                  1, /* write level */
14240a96aa3bSJed Brown                                                                  1, /* write rank */
14250a96aa3bSJed Brown                                                                  0, /* do not wrap rank */
14260a96aa3bSJed Brown                                                                  0, /* no scalar fields */
14270a96aa3bSJed Brown                                                                  0, /* no vector fields */
14280a96aa3bSJed Brown                                                                  pvtk));
142928b400f6SJacob Faibussowitsch       PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_cell_dataf() failed");
14300a96aa3bSJed Brown       PetscStackCallP4estReturn(footerr,p4est_vtk_write_footer,(pvtk));
143128b400f6SJacob Faibussowitsch       PetscCheck(!footerr,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_footer() failed");
14320a96aa3bSJed Brown     }
14330a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4est(p4est_geometry_destroy,(geom));
14349566063dSJacob Faibussowitsch     PetscCall(PetscFree(filenameStrip));
14350a96aa3bSJed Brown     break;
143698921bdaSJacob Faibussowitsch   default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
14370a96aa3bSJed Brown   }
14380a96aa3bSJed Brown   PetscFunctionReturn(0);
14390a96aa3bSJed Brown }
14400a96aa3bSJed Brown 
14410a96aa3bSJed Brown #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
14420a96aa3bSJed Brown static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer)
14430a96aa3bSJed Brown {
14440a96aa3bSJed Brown   DM             plex;
14450a96aa3bSJed Brown 
14460a96aa3bSJed Brown   PetscFunctionBegin;
14479566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14489566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14499566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14500a96aa3bSJed Brown   PetscFunctionReturn(0);
14510a96aa3bSJed Brown }
14520a96aa3bSJed Brown 
14530a96aa3bSJed Brown #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
14540a96aa3bSJed Brown static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer)
14550a96aa3bSJed Brown {
14560a96aa3bSJed Brown   DM             plex;
14570a96aa3bSJed Brown 
14580a96aa3bSJed Brown   PetscFunctionBegin;
14599566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
14609566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm, &plex));
14619566063dSJacob Faibussowitsch   PetscCall(DMView(plex, viewer));
14620a96aa3bSJed Brown   PetscFunctionReturn(0);
14630a96aa3bSJed Brown }
14640a96aa3bSJed Brown 
14650a96aa3bSJed Brown #define DMView_pforest _append_pforest(DMView)
14660a96aa3bSJed Brown static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer)
14670a96aa3bSJed Brown {
14680a96aa3bSJed Brown   PetscBool      isascii, isvtk, ishdf5, isglvis;
14690a96aa3bSJed Brown 
14700a96aa3bSJed Brown   PetscFunctionBegin;
14710a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
14720a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
14739566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii));
14749566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk));
14759566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5));
14769566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis));
14770a96aa3bSJed Brown   if (isascii) {
14789566063dSJacob Faibussowitsch     PetscCall(DMView_ASCII_pforest((PetscObject) dm,viewer));
14790a96aa3bSJed Brown   } else if (isvtk) {
14809566063dSJacob Faibussowitsch     PetscCall(DMView_VTK_pforest((PetscObject) dm,viewer));
14810a96aa3bSJed Brown   } else if (ishdf5) {
14829566063dSJacob Faibussowitsch     PetscCall(DMView_HDF5_pforest(dm, viewer));
14830a96aa3bSJed Brown   } else if (isglvis) {
14849566063dSJacob Faibussowitsch     PetscCall(DMView_GLVis_pforest(dm, viewer));
14850a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject) dm),PETSC_ERR_SUP,"Viewer not supported (not VTK, HDF5, or GLVis)");
14860a96aa3bSJed Brown   PetscFunctionReturn(0);
14870a96aa3bSJed Brown }
14880a96aa3bSJed Brown 
14890a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq)
14900a96aa3bSJed Brown {
14910a96aa3bSJed Brown   PetscInt       *ttf, f, t, g, count;
14920a96aa3bSJed Brown   PetscInt       numFacets;
14930a96aa3bSJed Brown 
14940a96aa3bSJed Brown   PetscFunctionBegin;
14950a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
14969566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(numFacets,&ttf));
14970a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
14980a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
14990a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
15000a96aa3bSJed Brown       if (ttf[g] == -1) {
15010a96aa3bSJed Brown         PetscInt ng;
15020a96aa3bSJed Brown 
15030a96aa3bSJed Brown         ttf[g]  = count++;
15040a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
15050a96aa3bSJed Brown         ttf[ng] = ttf[g];
15060a96aa3bSJed Brown       }
15070a96aa3bSJed Brown     }
15080a96aa3bSJed Brown   }
15090a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
15100a96aa3bSJed Brown   PetscFunctionReturn(0);
15110a96aa3bSJed Brown }
15120a96aa3bSJed Brown 
15130a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq)
15140a96aa3bSJed Brown {
15150a96aa3bSJed Brown   p4est_topidx_t       numTrees, numVerts, numCorns, numCtt;
15160a96aa3bSJed Brown   PetscSection         ctt;
15170a96aa3bSJed Brown #if defined(P4_TO_P8)
15180a96aa3bSJed Brown   p4est_topidx_t       numEdges, numEtt;
15190a96aa3bSJed Brown   PetscSection         ett;
15200a96aa3bSJed Brown   PetscInt             eStart, eEnd, e, ettSize;
15210a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES + P8EST_EDGES;
15220a96aa3bSJed Brown   PetscInt             edgeOff = 1 + P4EST_FACES;
15230a96aa3bSJed Brown #else
15240a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES;
15250a96aa3bSJed Brown #endif
15260a96aa3bSJed Brown   p4est_connectivity_t *conn;
15270a96aa3bSJed Brown   PetscInt             cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
15280a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
15290a96aa3bSJed Brown   PetscInt             *ttf;
15300a96aa3bSJed Brown 
15310a96aa3bSJed Brown   PetscFunctionBegin;
15320a96aa3bSJed Brown   /* 1: count objects, allocate */
15339566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd));
15349566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cEnd-cStart,&numTrees));
15350a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
15369566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd));
15379566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(vEnd-vStart,&numCorns));
15389566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&ctt));
15399566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ctt,vStart,vEnd));
15400a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
15410a96aa3bSJed Brown     PetscInt s;
15420a96aa3bSJed Brown 
15439566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
15440a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15450a96aa3bSJed Brown       PetscInt p = star[2*s];
15460a96aa3bSJed Brown 
15470a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15480a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
15490a96aa3bSJed Brown          * only protects against periodicity problems */
15509566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
155163a3b9bcSJacob 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);
15520a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
15530a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
15540a96aa3bSJed Brown 
15551dca8a05SBarry Smith           PetscCheck(cellVert >= vStart && cellVert < vEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: vertices");
15560a96aa3bSJed Brown           if (cellVert == v) {
15579566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(ctt,v,1));
15580a96aa3bSJed Brown           }
15590a96aa3bSJed Brown         }
15609566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15610a96aa3bSJed Brown       }
15620a96aa3bSJed Brown     }
15639566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
15640a96aa3bSJed Brown   }
15659566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ctt));
15669566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ctt,&cttSize));
15679566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(cttSize,&numCtt));
15680a96aa3bSJed Brown #if defined(P4_TO_P8)
15699566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,P4EST_DIM-1,&eStart,&eEnd));
15709566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(eEnd-eStart,&numEdges));
15719566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&ett));
15729566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(ett,eStart,eEnd));
15730a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
15740a96aa3bSJed Brown     PetscInt s;
15750a96aa3bSJed Brown 
15769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
15770a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
15780a96aa3bSJed Brown       PetscInt p = star[2*s];
15790a96aa3bSJed Brown 
15800a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
15810a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
15820a96aa3bSJed Brown          * only protects against periodicity problems */
15839566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
158408401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell with wrong closure size");
15850a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
15860a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
15870a96aa3bSJed Brown 
15881dca8a05SBarry Smith           PetscCheck(cellEdge >= eStart && cellEdge < eEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: edges");
15890a96aa3bSJed Brown           if (cellEdge == e) {
15909566063dSJacob Faibussowitsch             PetscCall(PetscSectionAddDof(ett,e,1));
15910a96aa3bSJed Brown           }
15920a96aa3bSJed Brown         }
15939566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
15940a96aa3bSJed Brown       }
15950a96aa3bSJed Brown     }
15969566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
15970a96aa3bSJed Brown   }
15989566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(ett));
15999566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(ett,&ettSize));
16009566063dSJacob Faibussowitsch   PetscCall(P4estTopidxCast(ettSize,&numEtt));
16010a96aa3bSJed Brown 
16020a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
16030a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p8est_connectivity_new,(numVerts,numTrees,numEdges,numEtt,numCorns,numCtt));
16040a96aa3bSJed Brown #else
16050a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p4est_connectivity_new,(numVerts,numTrees,numCorns,numCtt));
16060a96aa3bSJed Brown #endif
16070a96aa3bSJed Brown 
16080a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
16099566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(dm,1,&fStart,&fEnd));
16109566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1((cEnd-cStart) * P4EST_FACES,&ttf));
16110a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
16120a96aa3bSJed Brown     PetscInt       numSupp, s;
16130a96aa3bSJed Brown     PetscInt       myFace[2] = {-1, -1};
16140a96aa3bSJed Brown     PetscInt       myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
16150a96aa3bSJed Brown     const PetscInt *supp;
16160a96aa3bSJed Brown 
16179566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm, f, &numSupp));
16181dca8a05SBarry 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);
16199566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm, f, &supp));
16200a96aa3bSJed Brown 
16210a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16220a96aa3bSJed Brown       PetscInt p = supp[s];
16230a96aa3bSJed Brown 
16240a96aa3bSJed Brown       if (p >= cEnd) {
16250a96aa3bSJed Brown         numSupp--;
16260a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
16270a96aa3bSJed Brown         break;
16280a96aa3bSJed Brown       }
16290a96aa3bSJed Brown     }
16300a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
16310a96aa3bSJed Brown       PetscInt       p = supp[s], i;
16320a96aa3bSJed Brown       PetscInt       numCone;
16330a96aa3bSJed Brown       DMPolytopeType ct;
16340a96aa3bSJed Brown       const PetscInt *cone;
16350a96aa3bSJed Brown       const PetscInt *ornt;
16360a96aa3bSJed Brown       PetscInt       orient = PETSC_MIN_INT;
16370a96aa3bSJed Brown 
16389566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeSize(dm, p, &numCone));
163963a3b9bcSJacob 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);
16409566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCone(dm, p, &cone));
16419566063dSJacob Faibussowitsch       PetscCall(DMPlexGetCellType(dm, cone[0], &ct));
16429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetConeOrientation(dm, p, &ornt));
16430a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
16440a96aa3bSJed Brown         if (cone[i] == f) {
16450a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
16460a96aa3bSJed Brown           break;
16470a96aa3bSJed Brown         }
16480a96aa3bSJed Brown       }
164963a3b9bcSJacob Faibussowitsch       PetscCheck(i < P4EST_FACES,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %" PetscInt_FMT " faced %" PetscInt_FMT " mismatch",p,f);
16500a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
16510a96aa3bSJed Brown         DMPolytopeType ct;
16529566063dSJacob Faibussowitsch         PetscCall(DMPlexGetCellType(dm, p, &ct));
165363a3b9bcSJacob 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);
16540a96aa3bSJed Brown       }
16550a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
16560a96aa3bSJed Brown       if (numSupp == 1) {
16570a96aa3bSJed Brown         /* boundary faces indicated by self reference */
16580a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
16590a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t) PetscFaceToP4estFace[i];
16600a96aa3bSJed Brown       } else {
16610a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16620a96aa3bSJed Brown 
16630a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
16640a96aa3bSJed Brown         myFace[s] = PetscFaceToP4estFace[i];
16650a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
16660a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
16670a96aa3bSJed Brown         myOrnt[s] = DihedralCompose(N,orient,DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
16680a96aa3bSJed Brown       }
16690a96aa3bSJed Brown     }
16700a96aa3bSJed Brown     if (numSupp == 2) {
16710a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
16720a96aa3bSJed Brown         PetscInt       p = supp[s];
16730a96aa3bSJed Brown         PetscInt       orntAtoB;
16740a96aa3bSJed Brown         PetscInt       p4estOrient;
16750a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
16760a96aa3bSJed Brown 
16770a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
16780a96aa3bSJed Brown          * permutation of this cell-facet's cone */
16790a96aa3bSJed Brown         orntAtoB = DihedralCompose(N,DihedralInvert(N,myOrnt[1-s]),myOrnt[s]);
16800a96aa3bSJed Brown 
16810a96aa3bSJed Brown         /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
16820a96aa3bSJed Brown          * vertices around facet) */
16830a96aa3bSJed Brown #if !defined(P4_TO_P8)
16840a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
16850a96aa3bSJed Brown #else
16860a96aa3bSJed Brown         {
16870a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
16880a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
16890a96aa3bSJed Brown 
16900a96aa3bSJed Brown                                                                                            /* swap bits */
16910a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
16920a96aa3bSJed Brown         }
16930a96aa3bSJed Brown #endif
16940a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
16950a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
16960a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t) myFace[1 - s] + p4estOrient * P4EST_FACES;
16970a96aa3bSJed Brown       }
16980a96aa3bSJed Brown     }
16990a96aa3bSJed Brown   }
17000a96aa3bSJed Brown 
17010a96aa3bSJed Brown #if defined(P4_TO_P8)
17020a96aa3bSJed Brown   /* 3: visit every edge */
17030a96aa3bSJed Brown   conn->ett_offset[0] = 0;
17040a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
17050a96aa3bSJed Brown     PetscInt off, s;
17060a96aa3bSJed Brown 
17079566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ett,e,&off));
17080a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t) off;
17099566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
17100a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17110a96aa3bSJed Brown       PetscInt p = star[2 * s];
17120a96aa3bSJed Brown 
17130a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17149566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
171508401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
17160a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
17170a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
17180a96aa3bSJed Brown           PetscInt cellOrnt = closure[2 * (c + edgeOff) + 1];
17190a96aa3bSJed Brown           DMPolytopeType ct;
17200a96aa3bSJed Brown 
17219566063dSJacob Faibussowitsch           PetscCall(DMPlexGetCellType(dm, cellEdge, &ct));
17220a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
17230a96aa3bSJed Brown           if (cellEdge == e) {
17240a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
17250a96aa3bSJed Brown             PetscInt totalOrient;
17260a96aa3bSJed Brown 
17270a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
17280a96aa3bSJed Brown             totalOrient = DihedralCompose(2,cellOrnt,DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
17290a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
17300a96aa3bSJed Brown             totalOrient             = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
17310a96aa3bSJed Brown             conn->edge_to_tree[off] = (p4est_locidx_t) (p - cStart);
17320a96aa3bSJed Brown             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standart (see
17330a96aa3bSJed Brown              * p8est_connectivity.h) */
17340a96aa3bSJed Brown             conn->edge_to_edge[off++] = (int8_t) p4estEdge + P8EST_EDGES * totalOrient;
17350a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
17360a96aa3bSJed Brown           }
17370a96aa3bSJed Brown         }
17389566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17390a96aa3bSJed Brown       }
17400a96aa3bSJed Brown     }
17419566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star));
17420a96aa3bSJed Brown   }
17439566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ett));
17440a96aa3bSJed Brown #endif
17450a96aa3bSJed Brown 
17460a96aa3bSJed Brown   /* 4: visit every vertex */
17470a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
17480a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
17490a96aa3bSJed Brown     PetscInt off, s;
17500a96aa3bSJed Brown 
17519566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(ctt,v,&off));
17520a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t) off;
17539566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
17540a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
17550a96aa3bSJed Brown       PetscInt p = star[2 * s];
17560a96aa3bSJed Brown 
17570a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
17589566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
175908401ef6SPierre Jolivet         PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
17600a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
17610a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
17620a96aa3bSJed Brown 
17630a96aa3bSJed Brown           if (cellVert == v) {
17640a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
17650a96aa3bSJed Brown 
17660a96aa3bSJed Brown             conn->corner_to_tree[off]     = (p4est_locidx_t) (p - cStart);
17670a96aa3bSJed Brown             conn->corner_to_corner[off++] = (int8_t) p4estVert;
17680a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
17690a96aa3bSJed Brown           }
17700a96aa3bSJed Brown         }
17719566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure));
17720a96aa3bSJed Brown       }
17730a96aa3bSJed Brown     }
17749566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star));
17750a96aa3bSJed Brown   }
17769566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&ctt));
17770a96aa3bSJed Brown 
17780a96aa3bSJed Brown   /* 5: Compute the coordinates */
17790a96aa3bSJed Brown   {
17800a96aa3bSJed Brown     PetscInt     coordDim;
17810a96aa3bSJed Brown     Vec          coordVec;
17820a96aa3bSJed Brown     PetscSection coordSec;
17830a96aa3bSJed Brown     PetscBool    localized;
17840a96aa3bSJed Brown 
17859566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm, &coordDim));
17869566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocal(dm, &coordVec));
17879566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocalizedLocal(dm, &localized));
17889566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(dm, &coordSec));
17890a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
17900a96aa3bSJed Brown       PetscInt    dof;
17910a96aa3bSJed Brown       PetscScalar *cellCoords = NULL;
17920a96aa3bSJed Brown 
17939566063dSJacob Faibussowitsch       PetscCall(DMPlexVecGetClosure(dm, coordSec, coordVec, c, &dof, &cellCoords));
17941dca8a05SBarry Smith       PetscCheck(localized || dof == P4EST_CHILDREN * coordDim,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Need coordinates at the corners: (dof) %" PetscInt_FMT " != %d * %" PetscInt_FMT " (sdim)", dof, P4EST_CHILDREN, coordDim);
17950a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
17960a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
17970a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
17980a96aa3bSJed Brown 
17990a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
18000a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
18010a96aa3bSJed Brown         for (i = 0; i < 3; i++)   conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
18020a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
18030a96aa3bSJed Brown       }
18049566063dSJacob Faibussowitsch       PetscCall(DMPlexVecRestoreClosure(dm, coordSec, coordVec, c, &dof, &cellCoords));
18050a96aa3bSJed Brown     }
18060a96aa3bSJed Brown   }
18070a96aa3bSJed Brown 
18080a96aa3bSJed Brown #if defined(P4EST_ENABLE_DEBUG)
180908401ef6SPierre Jolivet   PetscCheck(p4est_connectivity_is_valid(conn),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Plex to p4est conversion failed");
18100a96aa3bSJed Brown #endif
18110a96aa3bSJed Brown 
18120a96aa3bSJed Brown   *connOut = conn;
18130a96aa3bSJed Brown 
18140a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
18150a96aa3bSJed Brown 
18160a96aa3bSJed Brown   PetscFunctionReturn(0);
18170a96aa3bSJed Brown }
18180a96aa3bSJed Brown 
18190a96aa3bSJed Brown static PetscErrorCode locidx_to_PetscInt(sc_array_t * array)
18200a96aa3bSJed Brown {
18210a96aa3bSJed Brown   sc_array_t *newarray;
18220a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18230a96aa3bSJed Brown 
18240a96aa3bSJed Brown   PetscFunctionBegin;
182508401ef6SPierre Jolivet   PetscCheck(array->elem_size == sizeof(p4est_locidx_t),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
18260a96aa3bSJed Brown 
18270a96aa3bSJed Brown   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(0);
18280a96aa3bSJed Brown 
18290a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscInt), array->elem_count);
18300a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18310a96aa3bSJed Brown     p4est_locidx_t il  = *((p4est_locidx_t*) sc_array_index (array, zz));
18320a96aa3bSJed Brown     PetscInt       *ip = (PetscInt*) sc_array_index (newarray, zz);
18330a96aa3bSJed Brown 
18340a96aa3bSJed Brown     *ip = (PetscInt) il;
18350a96aa3bSJed Brown   }
18360a96aa3bSJed Brown 
18370a96aa3bSJed Brown   sc_array_reset (array);
18380a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscInt), count);
18390a96aa3bSJed Brown   sc_array_copy (array, newarray);
18400a96aa3bSJed Brown   sc_array_destroy (newarray);
18410a96aa3bSJed Brown   PetscFunctionReturn(0);
18420a96aa3bSJed Brown }
18430a96aa3bSJed Brown 
18440a96aa3bSJed Brown static PetscErrorCode coords_double_to_PetscScalar(sc_array_t * array, PetscInt dim)
18450a96aa3bSJed Brown {
18460a96aa3bSJed Brown   sc_array_t *newarray;
18470a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18480a96aa3bSJed Brown 
18490a96aa3bSJed Brown   PetscFunctionBegin;
18501dca8a05SBarry Smith   PetscCheck(array->elem_size == 3 * sizeof(double),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong coordinate size");
18510a96aa3bSJed Brown #if !defined(PETSC_USE_COMPLEX)
18520a96aa3bSJed Brown   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(0);
18530a96aa3bSJed Brown #endif
18540a96aa3bSJed Brown 
18550a96aa3bSJed Brown   newarray = sc_array_new_size (dim * sizeof(PetscScalar), array->elem_count);
18560a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18570a96aa3bSJed Brown     int         i;
18580a96aa3bSJed Brown     double      *id = (double*) sc_array_index (array, zz);
18590a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar*) sc_array_index (newarray, zz);
18600a96aa3bSJed Brown 
18610a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
18620a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim,3); i++) ip[i] = (PetscScalar) id[i];
18630a96aa3bSJed Brown   }
18640a96aa3bSJed Brown 
18650a96aa3bSJed Brown   sc_array_reset (array);
18660a96aa3bSJed Brown   sc_array_init_size (array, dim * sizeof(PetscScalar), count);
18670a96aa3bSJed Brown   sc_array_copy (array, newarray);
18680a96aa3bSJed Brown   sc_array_destroy (newarray);
18690a96aa3bSJed Brown   PetscFunctionReturn(0);
18700a96aa3bSJed Brown }
18710a96aa3bSJed Brown 
18720a96aa3bSJed Brown static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t * array)
18730a96aa3bSJed Brown {
18740a96aa3bSJed Brown   sc_array_t *newarray;
18750a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
18760a96aa3bSJed Brown 
18770a96aa3bSJed Brown   PetscFunctionBegin;
18781dca8a05SBarry Smith   PetscCheck(array->elem_size == 2 * sizeof(p4est_locidx_t),PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
18790a96aa3bSJed Brown 
18800a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscSFNode), array->elem_count);
18810a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
18820a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t*) sc_array_index (array, zz);
18830a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode*) sc_array_index (newarray, zz);
18840a96aa3bSJed Brown 
18850a96aa3bSJed Brown     ip->rank  = (PetscInt) il[0];
18860a96aa3bSJed Brown     ip->index = (PetscInt) il[1];
18870a96aa3bSJed Brown   }
18880a96aa3bSJed Brown 
18890a96aa3bSJed Brown   sc_array_reset (array);
18900a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscSFNode), count);
18910a96aa3bSJed Brown   sc_array_copy (array, newarray);
18920a96aa3bSJed Brown   sc_array_destroy (newarray);
18930a96aa3bSJed Brown   PetscFunctionReturn(0);
18940a96aa3bSJed Brown }
18950a96aa3bSJed Brown 
18960a96aa3bSJed Brown static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM * plex)
18970a96aa3bSJed Brown {
18980a96aa3bSJed Brown   PetscFunctionBegin;
18990a96aa3bSJed Brown   {
19000a96aa3bSJed Brown     sc_array_t     *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
19010a96aa3bSJed Brown     sc_array_t     *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
19020a96aa3bSJed Brown     sc_array_t     *cones             = sc_array_new(sizeof(p4est_locidx_t));
19030a96aa3bSJed Brown     sc_array_t     *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
19040a96aa3bSJed Brown     sc_array_t     *coords            = sc_array_new(3 * sizeof(double));
19050a96aa3bSJed Brown     sc_array_t     *children          = sc_array_new(sizeof(p4est_locidx_t));
19060a96aa3bSJed Brown     sc_array_t     *parents           = sc_array_new(sizeof(p4est_locidx_t));
19070a96aa3bSJed Brown     sc_array_t     *childids          = sc_array_new(sizeof(p4est_locidx_t));
19080a96aa3bSJed Brown     sc_array_t     *leaves            = sc_array_new(sizeof(p4est_locidx_t));
19090a96aa3bSJed Brown     sc_array_t     *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
19100a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
19110a96aa3bSJed Brown 
19120a96aa3bSJed 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));
19130a96aa3bSJed Brown 
19149566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
19159566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
19169566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
19179566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
19189566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, P4EST_DIM));
19190a96aa3bSJed Brown 
19209566063dSJacob Faibussowitsch     PetscCall(DMPlexCreate(PETSC_COMM_SELF,plex));
19219566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(*plex,P4EST_DIM));
19229566063dSJacob 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));
19239566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(*plex));
19240a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
19250a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
19260a96aa3bSJed Brown     sc_array_destroy (cones);
19270a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
19280a96aa3bSJed Brown     sc_array_destroy (coords);
19290a96aa3bSJed Brown     sc_array_destroy (children);
19300a96aa3bSJed Brown     sc_array_destroy (parents);
19310a96aa3bSJed Brown     sc_array_destroy (childids);
19320a96aa3bSJed Brown     sc_array_destroy (leaves);
19330a96aa3bSJed Brown     sc_array_destroy (remotes);
19340a96aa3bSJed Brown   }
19350a96aa3bSJed Brown   PetscFunctionReturn(0);
19360a96aa3bSJed Brown }
19370a96aa3bSJed Brown 
19380a96aa3bSJed Brown #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
19390a96aa3bSJed Brown static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB,PetscInt *childB)
19400a96aa3bSJed Brown {
19410a96aa3bSJed Brown   PetscInt       coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
19420a96aa3bSJed Brown 
19430a96aa3bSJed Brown   PetscFunctionBegin;
19440a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
19450a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
19460a96aa3bSJed Brown     if (childB) *childB = childA;
19470a96aa3bSJed Brown     PetscFunctionReturn(0);
19480a96aa3bSJed Brown   }
19499566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd));
19506aad120cSJose E. Roman   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invariant under rotation */
19510a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
19520a96aa3bSJed Brown     if (childB) *childB = childA;
19530a96aa3bSJed Brown     PetscFunctionReturn(0);
19540a96aa3bSJed Brown   }
19550a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
19569566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd));
19570a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
19580a96aa3bSJed Brown   }
195963a3b9bcSJacob Faibussowitsch   PetscCheck(dim <= 2,PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %" PetscInt_FMT "-cells",dim);
196028b400f6SJacob Faibussowitsch   PetscCheck(dim,PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
19610a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
19620a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
19630a96aa3bSJed Brown     PetscInt       size, i, sA = -1, sB, sOrientB, sConeSize;
19640a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
19650a96aa3bSJed Brown 
19669566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupportSize(dm,childA,&size));
19679566063dSJacob Faibussowitsch     PetscCall(DMPlexGetSupport(dm,childA,&supp));
19680a96aa3bSJed Brown 
19690a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
19700a96aa3bSJed Brown     for (i = 0; i < size; i++) {
19710a96aa3bSJed Brown       PetscInt sParent;
19720a96aa3bSJed Brown 
19730a96aa3bSJed Brown       sA = supp[i];
19740a96aa3bSJed Brown       if (sA == parent) continue;
19759566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTreeParent(dm,sA,&sParent,NULL));
19760a96aa3bSJed Brown       if (sParent == parent) break;
19770a96aa3bSJed Brown     }
197808401ef6SPierre Jolivet     PetscCheck(i != size,PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
19790a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
19800a96aa3bSJed Brown      * parentOrientB */
19819566063dSJacob Faibussowitsch     PetscCall(DMReferenceTreeGetChildSymmetry_pforest(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB));
19829566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeSize(dm,sA,&sConeSize));
19839566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sA,&coneA));
19849566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCone(dm,sB,&coneB));
19859566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sA,&oA));
19869566063dSJacob Faibussowitsch     PetscCall(DMPlexGetConeOrientation(dm,sB,&oB));
19870a96aa3bSJed Brown     /* step through the cone of sA in natural order */
19880a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
19890a96aa3bSJed Brown       if (coneA[i] == childA) {
19900a96aa3bSJed Brown         /* if childA is at position i in coneA,
19910a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
19920a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
19930a96aa3bSJed Brown         if (childB) *childB = coneB[j];
19940a96aa3bSJed Brown         if (childOrientB) {
19950a96aa3bSJed Brown           DMPolytopeType ct;
19960a96aa3bSJed Brown           PetscInt       oBtrue;
19970a96aa3bSJed Brown 
19989566063dSJacob Faibussowitsch           PetscCall(DMPlexGetConeSize(dm,childA,&coneSize));
19990a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
20001dca8a05SBarry Smith           PetscCheck(coneSize == 0 || coneSize == 2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
20010a96aa3bSJed Brown           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
20020a96aa3bSJed Brown           /* we may have to flip an edge */
20030a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
20040a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
20050a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize,DMPolytopeConvertNewOrientation_Internal(ct, oA[i]),oBtrue);
20060a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
20070a96aa3bSJed Brown         }
20080a96aa3bSJed Brown         break;
20090a96aa3bSJed Brown       }
20100a96aa3bSJed Brown     }
201108401ef6SPierre Jolivet     PetscCheck(i != sConeSize,PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
20120a96aa3bSJed Brown     PetscFunctionReturn(0);
20130a96aa3bSJed Brown   }
20140a96aa3bSJed Brown   /* get the cone size and symmetry swap */
20159566063dSJacob Faibussowitsch   PetscCall(DMPlexGetConeSize(dm,parent,&coneSize));
20160a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
20170a96aa3bSJed Brown   if (dim == 2) {
20180a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
20190a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
20200a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
20210a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
20220a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
20230a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
20240a96aa3bSJed Brown   } else {
20250a96aa3bSJed Brown     oAvert     = parentOrientA;
20260a96aa3bSJed Brown     oBvert     = parentOrientB;
20270a96aa3bSJed Brown     ABswapVert = ABswap;
20280a96aa3bSJed Brown   }
20290a96aa3bSJed Brown   if (childB) {
20300a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
20310a96aa3bSJed Brown     PetscInt       p, posA = -1, numChildren, i;
20320a96aa3bSJed Brown     const PetscInt *children;
20330a96aa3bSJed Brown 
20340a96aa3bSJed Brown     /* count which position the child is in */
20359566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTreeChildren(dm,parent,&numChildren,&children));
20360a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
20370a96aa3bSJed Brown       p = children[i];
20380a96aa3bSJed Brown       if (p == childA) {
20390a96aa3bSJed Brown         if (dim == 1) {
20400a96aa3bSJed Brown           posA = i;
20410a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
20420a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
20430a96aa3bSJed Brown         }
20440a96aa3bSJed Brown         break;
20450a96aa3bSJed Brown       }
20460a96aa3bSJed Brown     }
20470a96aa3bSJed Brown     if (posA >= coneSize) {
20480a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not find childA in children of parent");
20490a96aa3bSJed Brown     } else {
20500a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
20510a96aa3bSJed Brown       PetscInt posB, childIdB;
20520a96aa3bSJed Brown 
20530a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
20540a96aa3bSJed Brown       if (dim == 1) {
20550a96aa3bSJed Brown         childIdB = posB;
20560a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
20570a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
20580a96aa3bSJed Brown       }
20590a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
20600a96aa3bSJed Brown     }
20610a96aa3bSJed Brown   }
20620a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
20630a96aa3bSJed Brown   PetscFunctionReturn(0);
20640a96aa3bSJed Brown }
20650a96aa3bSJed Brown 
20660a96aa3bSJed Brown #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
20670a96aa3bSJed Brown static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm)
20680a96aa3bSJed Brown {
20690a96aa3bSJed Brown   p4est_connectivity_t *refcube;
20700a96aa3bSJed Brown   p4est_t              *root, *refined;
20710a96aa3bSJed Brown   DM                   dmRoot, dmRefined;
20720a96aa3bSJed Brown   DM_Plex              *mesh;
20730a96aa3bSJed Brown   PetscMPIInt          rank;
20740a96aa3bSJed Brown 
20750a96aa3bSJed Brown   PetscFunctionBegin;
20760a96aa3bSJed Brown   PetscStackCallP4estReturn(refcube,p4est_connectivity_new_byname,("unit"));
20770a96aa3bSJed Brown   { /* [-1,1]^d geometry */
20780a96aa3bSJed Brown     PetscInt i, j;
20790a96aa3bSJed Brown 
20800a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
20810a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
20820a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
20830a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
20840a96aa3bSJed Brown       }
20850a96aa3bSJed Brown     }
20860a96aa3bSJed Brown   }
20870a96aa3bSJed Brown   PetscStackCallP4estReturn(root,p4est_new,(PETSC_COMM_SELF,refcube,0,NULL,NULL));
20880a96aa3bSJed Brown   PetscStackCallP4estReturn(refined,p4est_new_ext,(PETSC_COMM_SELF,refcube,0,1,1,0,NULL,NULL));
20899566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(root,&dmRoot));
20909566063dSJacob Faibussowitsch   PetscCall(P4estToPlex_Local(refined,&dmRefined));
20910a96aa3bSJed Brown   {
20920a96aa3bSJed Brown #if !defined(P4_TO_P8)
20930a96aa3bSJed Brown     PetscInt nPoints  = 25;
20940a96aa3bSJed Brown     PetscInt perm[25] = {0, 1, 2, 3,
20950a96aa3bSJed Brown                           4, 12, 8, 14,
20960a96aa3bSJed Brown                               6, 9, 15,
20970a96aa3bSJed Brown                           5, 13,    10,
20980a96aa3bSJed Brown                               7,    11,
20990a96aa3bSJed Brown                          16, 22, 20, 24,
21000a96aa3bSJed Brown                              17,     21,
21010a96aa3bSJed Brown                                  18, 23,
21020a96aa3bSJed Brown                                      19};
21030a96aa3bSJed Brown     PetscInt ident[25] = {0, 0, 0, 0,
21040a96aa3bSJed Brown                           1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0,
21050a96aa3bSJed Brown                           5, 6, 7, 8, 1, 2, 3, 4, 0};
21060a96aa3bSJed Brown #else
21070a96aa3bSJed Brown     PetscInt nPoints   = 125;
21080a96aa3bSJed Brown     PetscInt perm[125] = {0, 1, 2, 3, 4, 5, 6, 7,
21090a96aa3bSJed Brown                            8, 32, 16, 36, 24, 40,
21100a96aa3bSJed Brown                               12, 17, 37, 25, 41,
21110a96aa3bSJed Brown                            9, 33,     20, 26, 42,
21120a96aa3bSJed Brown                               13,     21, 27, 43,
21130a96aa3bSJed Brown                           10, 34, 18, 38,     28,
21140a96aa3bSJed Brown                               14, 19, 39,     29,
21150a96aa3bSJed Brown                           11, 35,     22,     30,
21160a96aa3bSJed Brown                               15,     23,     31,
21170a96aa3bSJed Brown                           44, 84, 76, 92, 52, 86, 68, 94, 60, 78, 70, 96,
21180a96aa3bSJed Brown                           45, 85, 77, 93,     54,     72,     62,     74,
21190a96aa3bSJed Brown                               46,     80, 53, 87, 69, 95,         64, 82,
21200a96aa3bSJed Brown                               47,     81,     55,     73,             66,
21210a96aa3bSJed Brown                                   48, 88,         56, 90, 61, 79, 71, 97,
21220a96aa3bSJed Brown                                   49, 89,             58,     63,     75,
21230a96aa3bSJed Brown                                       50,         57, 91,         65, 83,
21240a96aa3bSJed Brown                                       51,             59,             67,
21250a96aa3bSJed Brown                            98, 106, 110, 122, 114, 120, 118, 124,
21260a96aa3bSJed Brown                                 99,      111,      115,      119,
21270a96aa3bSJed Brown                                     100, 107,           116, 121,
21280a96aa3bSJed Brown                                          101,                117,
21290a96aa3bSJed Brown                                               102, 108, 112, 123,
21300a96aa3bSJed Brown                                                    103,      113,
21310a96aa3bSJed Brown                                                         104, 109,
21320a96aa3bSJed Brown                                                              105};
21330a96aa3bSJed Brown     PetscInt ident[125] = {0, 0, 0, 0, 0, 0, 0, 0,
21340a96aa3bSJed Brown                            1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6,
21350a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
21360a96aa3bSJed 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,
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,
21390a96aa3bSJed Brown                            19, 20, 21, 22, 23, 24, 25, 26,
21400a96aa3bSJed Brown                            7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
21410a96aa3bSJed Brown                            1, 2, 3, 4, 5, 6,
21420a96aa3bSJed Brown                            0};
21430a96aa3bSJed Brown 
21440a96aa3bSJed Brown #endif
21450a96aa3bSJed Brown     IS permIS;
21460a96aa3bSJed Brown     DM dmPerm;
21470a96aa3bSJed Brown 
21489566063dSJacob Faibussowitsch     PetscCall(ISCreateGeneral(PETSC_COMM_SELF,nPoints,perm,PETSC_USE_POINTER,&permIS));
21499566063dSJacob Faibussowitsch     PetscCall(DMPlexPermute(dmRefined,permIS,&dmPerm));
21500a96aa3bSJed Brown     if (dmPerm) {
21519566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&dmRefined));
21520a96aa3bSJed Brown       dmRefined = dmPerm;
21530a96aa3bSJed Brown     }
21549566063dSJacob Faibussowitsch     PetscCall(ISDestroy(&permIS));
21550a96aa3bSJed Brown     {
21560a96aa3bSJed Brown       PetscInt p;
21579566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRoot,"identity"));
21589566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(dmRefined,"identity"));
21590a96aa3bSJed Brown       for (p = 0; p < P4EST_INSUL; p++) {
21609566063dSJacob Faibussowitsch         PetscCall(DMSetLabelValue(dmRoot,"identity",p,p));
21610a96aa3bSJed Brown       }
21620a96aa3bSJed Brown       for (p = 0; p < nPoints; p++) {
21639566063dSJacob Faibussowitsch         PetscCall(DMSetLabelValue(dmRefined,"identity",p,ident[p]));
21640a96aa3bSJed Brown       }
21650a96aa3bSJed Brown     }
21660a96aa3bSJed Brown   }
21679566063dSJacob Faibussowitsch   PetscCall(DMPlexCreateReferenceTree_Union(dmRoot,dmRefined,"identity",dm));
21680a96aa3bSJed Brown   mesh                   = (DM_Plex*) (*dm)->data;
21690a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
21709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
21710a96aa3bSJed Brown   if (rank == 0) {
21729566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRoot,   NULL,"-dm_p4est_ref_root_view"));
21739566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_refined_view"));
21749566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_tree_view"));
21750a96aa3bSJed Brown   }
21769566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRefined));
21779566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&dmRoot));
21780a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(refined));
21790a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(root));
21800a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,(refcube));
21810a96aa3bSJed Brown   PetscFunctionReturn(0);
21820a96aa3bSJed Brown }
21830a96aa3bSJed Brown 
21840a96aa3bSJed Brown static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB)
21850a96aa3bSJed Brown {
21860a96aa3bSJed Brown   void          *ctx;
21870a96aa3bSJed Brown   PetscInt       num;
21880a96aa3bSJed Brown   PetscReal      val;
21890a96aa3bSJed Brown 
21900a96aa3bSJed Brown   PetscFunctionBegin;
21919566063dSJacob Faibussowitsch   PetscCall(DMGetApplicationContext(dmA,&ctx));
21929566063dSJacob Faibussowitsch   PetscCall(DMSetApplicationContext(dmB,ctx));
21939566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmA,dmB));
21949566063dSJacob Faibussowitsch   PetscCall(DMGetOutputSequenceNumber(dmA,&num,&val));
21959566063dSJacob Faibussowitsch   PetscCall(DMSetOutputSequenceNumber(dmB,num,val));
21960a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
21979566063dSJacob Faibussowitsch     PetscCall(DMClearLocalVectors(dmB));
21989566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->localSection));
21999566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->localSection)));
22000a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
22019566063dSJacob Faibussowitsch     PetscCall(DMClearGlobalVectors(dmB));
22029566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->globalSection));
22039566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->globalSection)));
22040a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
22059566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.section));
22069566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&(dmB->defaultConstraint.section)));
22073b8ba7d1SJed Brown     dmB->defaultConstraint.section = dmA->defaultConstraint.section;
22089566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->defaultConstraint.mat));
22099566063dSJacob Faibussowitsch     PetscCall(MatDestroy(&(dmB->defaultConstraint.mat)));
22103b8ba7d1SJed Brown     dmB->defaultConstraint.mat = dmA->defaultConstraint.mat;
22119566063dSJacob Faibussowitsch     if (dmA->map) PetscCall(PetscLayoutReference(dmA->map, &dmB->map));
22120a96aa3bSJed Brown   }
22130a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
22149566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)dmA->sectionSF));
22159566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&dmB->sectionSF));
22160a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
22170a96aa3bSJed Brown   }
22180a96aa3bSJed Brown   PetscFunctionReturn(0);
22190a96aa3bSJed Brown }
22200a96aa3bSJed Brown 
22210a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
22220a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm,p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF)
22230a96aa3bSJed Brown {
22240a96aa3bSJed Brown   PetscInt       startF, endF, startC, endC, p, nLeaves;
22250a96aa3bSJed Brown   PetscSFNode    *leaves;
22260a96aa3bSJed Brown   PetscSF        sf;
22270a96aa3bSJed Brown   PetscInt       *recv, *send;
22280a96aa3bSJed Brown   PetscMPIInt    tag;
22290a96aa3bSJed Brown   MPI_Request    *recvReqs, *sendReqs;
22300a96aa3bSJed Brown   PetscSection   section;
22310a96aa3bSJed Brown 
22320a96aa3bSJed Brown   PetscFunctionBegin;
22339566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estF,p4estC,&startC,&endC));
22349566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2*(endC-startC),&recv,endC-startC,&recvReqs));
22359566063dSJacob Faibussowitsch   PetscCall(PetscCommGetNewTag(comm,&tag));
22360a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
22370a96aa3bSJed Brown     recvReqs[p-startC] = MPI_REQUEST_NULL; /* just in case we don't initiate a receive */
22380a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p+1]) { /* empty coarse partition */
22390a96aa3bSJed Brown       recv[2*(p-startC)]   = 0;
22400a96aa3bSJed Brown       recv[2*(p-startC)+1] = 0;
22410a96aa3bSJed Brown       continue;
22420a96aa3bSJed Brown     }
22430a96aa3bSJed Brown 
22449566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Irecv(&recv[2*(p-startC)],2,MPIU_INT,p,tag,comm,&recvReqs[p-startC]));
22450a96aa3bSJed Brown   }
22469566063dSJacob Faibussowitsch   PetscCall(DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estC,p4estF,&startF,&endF));
22479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(2*(endF-startF),&send,endF-startF,&sendReqs));
22480a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
22490a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
22500a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
22510a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p+1];
22520a96aa3bSJed Brown     PetscInt         tStart       = (PetscInt) myFineStart->p.which_tree;
22530a96aa3bSJed Brown     PetscInt         tEnd         = (PetscInt) myFineEnd->p.which_tree;
22540a96aa3bSJed Brown     PetscInt         firstCell    = -1, lastCell = -1;
22550a96aa3bSJed Brown     p4est_tree_t     *treeStart   = &(((p4est_tree_t*) p4estC->trees->array)[tStart]);
22560a96aa3bSJed Brown     p4est_tree_t     *treeEnd     = (size_t) tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t*) p4estC->trees->array)[tEnd]) : NULL;
22570a96aa3bSJed Brown     ssize_t          overlapIndex;
22580a96aa3bSJed Brown 
22590a96aa3bSJed Brown     sendReqs[p-startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
22600a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p+1]) continue;
22610a96aa3bSJed Brown 
22620a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
22630a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
22640a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeStart->quadrants),myFineStart,p4est_quadrant_disjoint));
22650a96aa3bSJed Brown       if (overlapIndex < 0) {
22660a96aa3bSJed Brown         firstCell = 0;
22670a96aa3bSJed Brown       } else {
22680a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
22690a96aa3bSJed Brown       }
22700a96aa3bSJed Brown     } else {
22710a96aa3bSJed Brown       firstCell = 0;
22720a96aa3bSJed Brown     }
22730a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
22740a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeEnd->quadrants),myFineEnd,p4est_quadrant_disjoint));
22750a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
22760a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
22770a96aa3bSJed Brown       } else {
22780a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t*) treeEnd->quadrants.array)[overlapIndex]);
22790a96aa3bSJed Brown         p4est_quadrant_t first_desc;
22800a96aa3bSJed Brown         int              equal;
22810a96aa3bSJed Brown 
22820a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_first_descendant,(container,&first_desc,P4EST_QMAXLEVEL));
22830a96aa3bSJed Brown         PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(myFineEnd,&first_desc));
22840a96aa3bSJed Brown         if (equal) {
22850a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
22860a96aa3bSJed Brown         } else {
22870a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
22880a96aa3bSJed Brown         }
22890a96aa3bSJed Brown       }
22900a96aa3bSJed Brown     } else {
22910a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
22920a96aa3bSJed Brown     }
22930a96aa3bSJed Brown     send[2*(p-startF)]   = firstCell;
22940a96aa3bSJed Brown     send[2*(p-startF)+1] = lastCell - firstCell;
22959566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Isend(&send[2*(p-startF)],2,MPIU_INT,p,tag,comm,&sendReqs[p-startF]));
22960a96aa3bSJed Brown   }
22979566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endC-startC),recvReqs,MPI_STATUSES_IGNORE));
22989566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&section));
22999566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(section,startC,endC));
23000a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
23010a96aa3bSJed Brown     PetscInt numCells = recv[2*(p-startC)+1];
23029566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(section,p,numCells));
23030a96aa3bSJed Brown   }
23049566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(section));
23059566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(section,&nLeaves));
23069566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(nLeaves,&leaves));
23070a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
23080a96aa3bSJed Brown     PetscInt firstCell = recv[2*(p-startC)];
23090a96aa3bSJed Brown     PetscInt numCells  = recv[2*(p-startC)+1];
23100a96aa3bSJed Brown     PetscInt off, i;
23110a96aa3bSJed Brown 
23129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(section,p,&off));
23130a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
23140a96aa3bSJed Brown       leaves[off+i].rank  = p;
23150a96aa3bSJed Brown       leaves[off+i].index = firstCell + i;
23160a96aa3bSJed Brown     }
23170a96aa3bSJed Brown   }
23189566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(comm,&sf));
23199566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf,cEnd-cStart,nLeaves,NULL,PETSC_OWN_POINTER,leaves,PETSC_OWN_POINTER));
23209566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&section));
23219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Waitall((PetscMPIInt)(endF-startF),sendReqs,MPI_STATUSES_IGNORE));
23229566063dSJacob Faibussowitsch   PetscCall(PetscFree2(send,sendReqs));
23239566063dSJacob Faibussowitsch   PetscCall(PetscFree2(recv,recvReqs));
23240a96aa3bSJed Brown   *coveringSF = sf;
23250a96aa3bSJed Brown   PetscFunctionReturn(0);
23260a96aa3bSJed Brown }
23270a96aa3bSJed Brown 
23280a96aa3bSJed Brown /* closure points for locally-owned cells */
23290a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints,PetscBool redirect)
23300a96aa3bSJed Brown {
23310a96aa3bSJed Brown   PetscInt          cStart, cEnd;
23320a96aa3bSJed Brown   PetscInt          count, c;
23330a96aa3bSJed Brown   PetscMPIInt       rank;
23340a96aa3bSJed Brown   PetscInt          closureSize = -1;
23350a96aa3bSJed Brown   PetscInt          *closure    = NULL;
23360a96aa3bSJed Brown   PetscSF           pointSF;
23370a96aa3bSJed Brown   PetscInt          nleaves, nroots;
23380a96aa3bSJed Brown   const PetscInt    *ilocal;
23390a96aa3bSJed Brown   const PetscSFNode *iremote;
23400a96aa3bSJed Brown   DM                plex;
23410a96aa3bSJed Brown   DM_Forest         *forest;
23420a96aa3bSJed Brown   DM_Forest_pforest *pforest;
23430a96aa3bSJed Brown 
23440a96aa3bSJed Brown   PetscFunctionBegin;
23450a96aa3bSJed Brown   forest            = (DM_Forest *) dm->data;
23460a96aa3bSJed Brown   pforest           = (DM_Forest_pforest *) forest->data;
23470a96aa3bSJed Brown   cStart            = pforest->cLocalStart;
23480a96aa3bSJed Brown   cEnd              = pforest->cLocalEnd;
23499566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
23509566063dSJacob Faibussowitsch   PetscCall(DMGetPointSF(dm,&pointSF));
23519566063dSJacob Faibussowitsch   PetscCall(PetscSFGetGraph(pointSF,&nroots,&nleaves,&ilocal,&iremote));
23520a96aa3bSJed Brown   nleaves           = PetscMax(0,nleaves);
23530a96aa3bSJed Brown   nroots            = PetscMax(0,nroots);
23540a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
23559566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(*numClosurePoints,closurePoints));
23569566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
23570a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
23580a96aa3bSJed Brown     PetscInt i;
23599566063dSJacob Faibussowitsch     PetscCall(DMPlexGetTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure));
23600a96aa3bSJed Brown 
23610a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
23620a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
23630a96aa3bSJed Brown       PetscInt loc = -1;
23640a96aa3bSJed Brown 
23659566063dSJacob Faibussowitsch       PetscCall(PetscFindInt(p,nleaves,ilocal,&loc));
23660a96aa3bSJed Brown       if (redirect && loc >= 0) {
23670a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
23680a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
23690a96aa3bSJed Brown       } else {
23700a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
23710a96aa3bSJed Brown         (*closurePoints)[count].index = p;
23720a96aa3bSJed Brown       }
23730a96aa3bSJed Brown     }
23749566063dSJacob Faibussowitsch     PetscCall(DMPlexRestoreTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure));
23750a96aa3bSJed Brown   }
23760a96aa3bSJed Brown   PetscFunctionReturn(0);
23770a96aa3bSJed Brown }
23780a96aa3bSJed Brown 
23790a96aa3bSJed Brown static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type)
23800a96aa3bSJed Brown {
23810a96aa3bSJed Brown   PetscMPIInt i;
23820a96aa3bSJed Brown 
23830a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
23840a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode*)a;
23850a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode*)b;
23860a96aa3bSJed Brown 
23870a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
23880a96aa3bSJed Brown   }
23890a96aa3bSJed Brown }
23900a96aa3bSJed Brown 
23910a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
23920a96aa3bSJed Brown {
23930a96aa3bSJed Brown   MPI_Comm          comm;
23940a96aa3bSJed Brown   PetscMPIInt       rank, size;
23950a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
23960a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
23970a96aa3bSJed Brown   PetscInt          numClosureIndices;
23980a96aa3bSJed Brown   PetscInt          numClosurePointsC, numClosurePointsF;
23990a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
24000a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
24010a96aa3bSJed Brown   p4est_quadrant_t  **treeQuads;
24020a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
24030a96aa3bSJed Brown   MPI_Datatype      nodeType;
24040a96aa3bSJed Brown   MPI_Datatype      nodeClosureType;
24050a96aa3bSJed Brown   MPI_Op            sfNodeReduce;
24060a96aa3bSJed Brown   p4est_topidx_t    fltF, lltF, t;
24070a96aa3bSJed Brown   DM                plexC, plexF;
24080a96aa3bSJed Brown   PetscInt          pStartF, pEndF, pStartC, pEndC;
24090a96aa3bSJed Brown   PetscBool         saveInCoarse = PETSC_FALSE;
24100a96aa3bSJed Brown   PetscBool         saveInFine   = PETSC_FALSE;
24110a96aa3bSJed Brown   PetscBool         formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
24120a96aa3bSJed Brown   PetscInt          *cids        = NULL;
24130a96aa3bSJed Brown 
24140a96aa3bSJed Brown   PetscFunctionBegin;
24150a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
24160a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
24170a96aa3bSJed Brown   p4estC   = pforestC->forest;
24180a96aa3bSJed Brown   p4estF   = pforestF->forest;
241908401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo,PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
24200a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
24219566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
24229566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_size(comm,&size));
24239566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine,&plexF));
24249566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF,&pStartF,&pEndF));
24259566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse,&plexC));
24269566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC,&pStartC,&pEndC));
24270a96aa3bSJed Brown   { /* check if the results have been cached */
24280a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
24290a96aa3bSJed Brown 
24309566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(coarse,&adaptCoarse));
24319566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityForest(fine,&adaptFine));
24320a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
24330a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
24349566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestC->pointSelfToAdaptSF)));
24350a96aa3bSJed Brown         *sf  = pforestC->pointSelfToAdaptSF;
24360a96aa3bSJed Brown         if (childIds) {
24379566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
24389566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids,pforestC->pointSelfToAdaptCids,pEndF-pStartF));
24390a96aa3bSJed Brown           *childIds = cids;
24400a96aa3bSJed Brown         }
24410a96aa3bSJed Brown         PetscFunctionReturn(0);
24420a96aa3bSJed Brown       } else {
24430a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
24440a96aa3bSJed Brown         formCids     = PETSC_TRUE;
24450a96aa3bSJed Brown       }
24460a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
24470a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
24489566063dSJacob Faibussowitsch         PetscCall(PetscObjectReference((PetscObject)(pforestF->pointAdaptToSelfSF)));
24490a96aa3bSJed Brown         *sf  = pforestF->pointAdaptToSelfSF;
24500a96aa3bSJed Brown         if (childIds) {
24519566063dSJacob Faibussowitsch           PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
24529566063dSJacob Faibussowitsch           PetscCall(PetscArraycpy(cids,pforestF->pointAdaptToSelfCids,pEndF-pStartF));
24530a96aa3bSJed Brown           *childIds = cids;
24540a96aa3bSJed Brown         }
24550a96aa3bSJed Brown         PetscFunctionReturn(0);
24560a96aa3bSJed Brown       } else {
24570a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
24580a96aa3bSJed Brown         formCids   = PETSC_TRUE;
24590a96aa3bSJed Brown       }
24600a96aa3bSJed Brown     }
24610a96aa3bSJed Brown   }
24620a96aa3bSJed Brown 
24630a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
24640a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
24650a96aa3bSJed Brown   /* create the datatype */
24669566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(2,MPIU_INT,&nodeType));
24679566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeType));
24689566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_create(DMPforestMaxSFNode,PETSC_FALSE,&sfNodeReduce));
24699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_contiguous(numClosureIndices*2,MPIU_INT,&nodeClosureType));
24709566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_commit(&nodeClosureType));
24710a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
24720a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
24739566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(coarse,numClosureIndices,&numClosurePointsC,&closurePointsC,PETSC_TRUE));
24749566063dSJacob Faibussowitsch   PetscCall(DMPforestGetCellSFNodes(fine  ,numClosureIndices,&numClosurePointsF,&closurePointsF,PETSC_FALSE));
24750a96aa3bSJed Brown   /* create pointers for tree lists */
24760a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
24770a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
24789566063dSJacob Faibussowitsch   PetscCall(PetscCalloc2(lltF + 1  - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts));
24790a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
24800a96aa3bSJed Brown   if (size > 1) {
24810a96aa3bSJed Brown     PetscInt p;
24820a96aa3bSJed Brown 
24830a96aa3bSJed Brown     for (p = 0; p < size; p++) {
24840a96aa3bSJed Brown       int equal;
24850a96aa3bSJed Brown 
24860a96aa3bSJed Brown       PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal_piggy,(&p4estC->global_first_position[p],&p4estF->global_first_position[p]));
24870a96aa3bSJed Brown       if (!equal) break;
24880a96aa3bSJed Brown     }
24890a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
24900a96aa3bSJed Brown       PetscInt         cStartC, cEndC;
24910a96aa3bSJed Brown       PetscSF          coveringSF;
24920a96aa3bSJed Brown       PetscInt         nleaves;
24930a96aa3bSJed Brown       PetscInt         count;
24940a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
24950a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
24960a96aa3bSJed Brown       p4est_topidx_t   fltC = p4estC->first_local_tree;
24970a96aa3bSJed Brown       p4est_topidx_t   lltC = p4estC->last_local_tree;
24980a96aa3bSJed Brown       p4est_topidx_t   t;
24990a96aa3bSJed Brown       PetscMPIInt      blockSizes[4]   = {P4EST_DIM,2,1,1};
25000a96aa3bSJed Brown       MPI_Aint         blockOffsets[4] = {offsetof(p4est_quadrant_t,x),
25010a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,level),
25020a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,pad16),
25030a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,p)};
25040a96aa3bSJed Brown       MPI_Datatype     blockTypes[4] = {MPI_INT32_T,MPI_INT8_T,MPI_INT16_T,MPI_INT32_T/* p.which_tree */};
25050a96aa3bSJed Brown       MPI_Datatype     quadStruct,quadType;
25060a96aa3bSJed Brown 
25079566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC,0,&cStartC,&cEndC));
25089566063dSJacob Faibussowitsch       PetscCall(DMPforestGetCellCoveringSF(comm,p4estC,p4estF,pforestC->cLocalStart,pforestC->cLocalEnd,&coveringSF));
25099566063dSJacob Faibussowitsch       PetscCall(PetscSFGetGraph(coveringSF,NULL,&nleaves,NULL,NULL));
25109566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numClosureIndices*nleaves,&newClosurePointsC));
25119566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&coverQuads));
25129566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(cEndC-cStartC,&coverQuadsSend));
25130a96aa3bSJed Brown       count = 0;
25140a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
25150a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
25160a96aa3bSJed Brown         PetscInt     q;
25170a96aa3bSJed Brown 
25189566063dSJacob Faibussowitsch         PetscCall(PetscMemcpy(&coverQuadsSend[count],tree->quadrants.array,tree->quadrants.elem_count * sizeof(p4est_quadrant_t)));
25190a96aa3bSJed Brown         for (q = 0; (size_t) q < tree->quadrants.elem_count; q++) coverQuadsSend[count+q].p.which_tree = t;
25200a96aa3bSJed Brown         count += tree->quadrants.elem_count;
25210a96aa3bSJed Brown       }
25220a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
25230a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
25240a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
25250a96aa3bSJed Brown        */
25269566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_struct(4,blockSizes,blockOffsets,blockTypes,&quadStruct));
25279566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_create_resized(quadStruct,0,sizeof(p4est_quadrant_t),&quadType));
25289566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_commit(&quadType));
25299566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE));
25309566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE));
25319566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE));
25329566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE));
25339566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadStruct));
25349566063dSJacob Faibussowitsch       PetscCallMPI(MPI_Type_free(&quadType));
25359566063dSJacob Faibussowitsch       PetscCall(PetscFree(coverQuadsSend));
25369566063dSJacob Faibussowitsch       PetscCall(PetscFree(closurePointsC));
25379566063dSJacob Faibussowitsch       PetscCall(PetscSFDestroy(&coveringSF));
25380a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
25390a96aa3bSJed Brown 
25400a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
25410a96aa3bSJed Brown       {
25420a96aa3bSJed Brown         PetscInt q;
25430a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
25440a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
25450a96aa3bSJed Brown           if (!treeQuadCounts[t-fltF]++) treeQuads[t-fltF] = &coverQuads[q];
25460a96aa3bSJed Brown         }
25470a96aa3bSJed Brown       }
25480a96aa3bSJed Brown     }
25490a96aa3bSJed Brown   }
25500a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
25510a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
25520a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
25530a96aa3bSJed Brown 
25540a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
25550a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t*) tree->quadrants.array;
25560a96aa3bSJed Brown     }
25570a96aa3bSJed Brown   }
25580a96aa3bSJed Brown 
25590a96aa3bSJed Brown   {
25600a96aa3bSJed Brown     PetscInt    p;
25610a96aa3bSJed Brown     PetscInt    cLocalStartF;
25620a96aa3bSJed Brown     PetscSF     pointSF;
25630a96aa3bSJed Brown     PetscSFNode *roots;
25640a96aa3bSJed Brown     PetscInt    *rootType;
25650a96aa3bSJed Brown     DM          refTree = NULL;
25660a96aa3bSJed Brown     DMLabel     canonical;
25670a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
25680a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
25690a96aa3bSJed Brown     PetscInt    coarseOffset;
25700a96aa3bSJed Brown     PetscInt    numCoarseQuads;
25710a96aa3bSJed Brown 
25729566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF-pStartF,&roots));
25739566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(pEndF-pStartF,&rootType));
25749566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(fine,&pointSF));
25750a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
25760a96aa3bSJed Brown       roots[p-pStartF].rank  = -1;
25770a96aa3bSJed Brown       roots[p-pStartF].index = -1;
25780a96aa3bSJed Brown       rootType[p-pStartF]    = -1;
25790a96aa3bSJed Brown     }
25800a96aa3bSJed Brown     if (formCids) {
25810a96aa3bSJed Brown       PetscInt child;
25820a96aa3bSJed Brown 
25839566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&cids));
25840a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
25859566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF,&refTree));
25869566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure));
25870a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
25889566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]));
25890a96aa3bSJed Brown       }
25909566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(refTree,"canonical",&canonical));
25910a96aa3bSJed Brown     }
25920a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
25930a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
25940a96aa3bSJed Brown       p4est_tree_t     *tree        = &(((p4est_tree_t*) p4estF->trees->array)[t]);
25950a96aa3bSJed Brown       PetscInt         numFineQuads = tree->quadrants.elem_count;
25960a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads = treeQuads[t - fltF];
25970a96aa3bSJed Brown       p4est_quadrant_t *fineQuads   = (p4est_quadrant_t*) tree->quadrants.array;
25980a96aa3bSJed Brown       PetscInt         i, coarseCount = 0;
25990a96aa3bSJed Brown       PetscInt         offset = tree->quadrants_offset;
26000a96aa3bSJed Brown       sc_array_t       coarseQuadsArray;
26010a96aa3bSJed Brown 
26020a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
26030a96aa3bSJed Brown       PetscStackCallP4est(sc_array_init_data,(&coarseQuadsArray,coarseQuads,sizeof(p4est_quadrant_t),(size_t) numCoarseQuads));
26040a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
26050a96aa3bSJed Brown         PetscInt         c     = i + offset;
26060a96aa3bSJed Brown         p4est_quadrant_t *quad = &fineQuads[i];
26070a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
26080a96aa3bSJed Brown         ssize_t          disjoint = -1;
26090a96aa3bSJed Brown 
26100a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
26110a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
26120a96aa3bSJed Brown           PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
26130a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
26140a96aa3bSJed Brown         }
261508401ef6SPierre Jolivet         PetscCheck(disjoint == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"did not find overlapping coarse quad");
26160a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
26170a96aa3bSJed Brown           if (transferIdent) { /* find corners */
26180a96aa3bSJed Brown             PetscInt j = 0;
26190a96aa3bSJed Brown 
26200a96aa3bSJed Brown             do {
26210a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
26220a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
26230a96aa3bSJed Brown                 int              equal;
26240a96aa3bSJed Brown 
26250a96aa3bSJed Brown                 PetscStackCallP4est(p4est_quadrant_corner_descendant,(quad,&cornerQuad,j,quadCoarse->level));
26260a96aa3bSJed Brown                 PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(&cornerQuad,quadCoarse));
26270a96aa3bSJed Brown                 if (equal) {
26280a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
26290a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
26300a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
26310a96aa3bSJed Brown 
26320a96aa3bSJed Brown                   roots[p-pStartF]    = q;
26330a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
26340a96aa3bSJed Brown                   cids[p-pStartF]     = -1;
26350a96aa3bSJed Brown                   j++;
26360a96aa3bSJed Brown                 }
26370a96aa3bSJed Brown               }
26380a96aa3bSJed Brown               coarseCount++;
26390a96aa3bSJed Brown               disjoint = 1;
26400a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
26410a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
26420a96aa3bSJed Brown                 PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
26430a96aa3bSJed Brown               }
26440a96aa3bSJed Brown             } while (!disjoint);
26450a96aa3bSJed Brown           }
26460a96aa3bSJed Brown           continue;
26470a96aa3bSJed Brown         }
26480a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
26490a96aa3bSJed Brown           PetscInt j;
26500a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
26510a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
26520a96aa3bSJed Brown 
26530a96aa3bSJed Brown             roots[p-pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
26540a96aa3bSJed Brown             rootType[p-pStartF] = PETSC_MAX_INT; /* unconditionally accept */
26550a96aa3bSJed Brown             cids[p-pStartF]     = -1;
26560a96aa3bSJed Brown           }
26570a96aa3bSJed Brown         } else {
26580a96aa3bSJed Brown           PetscInt levelDiff = quad->level - quadCoarse->level;
26590a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
26600a96aa3bSJed Brown 
26610a96aa3bSJed Brown           if (formCids) {
26620a96aa3bSJed Brown             PetscInt cl;
26630a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
26640a96aa3bSJed Brown             int      cid;
26650a96aa3bSJed Brown 
266608401ef6SPierre Jolivet             PetscCheck(levelDiff <= 1,PETSC_COMM_SELF,PETSC_ERR_USER,"Recursive child ids not implemented");
26670a96aa3bSJed Brown             PetscStackCallP4estReturn(cid,p4est_quadrant_child_id,(quad));
26689566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure));
26690a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
26700a96aa3bSJed Brown               PetscInt p      = pointClosure[2 * cl];
26710a96aa3bSJed Brown               PetscInt point  = childClosures[cid][2 * cl];
26720a96aa3bSJed Brown               PetscInt ornt   = childClosures[cid][2 * cl + 1];
26730a96aa3bSJed Brown               PetscInt newcid = -1;
26740a96aa3bSJed Brown               DMPolytopeType ct;
26750a96aa3bSJed Brown 
26760a96aa3bSJed Brown               if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
26779566063dSJacob Faibussowitsch               PetscCall(DMPlexGetCellType(refTree, point, &ct));
26780a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
26790a96aa3bSJed Brown               if (!cl) {
26800a96aa3bSJed Brown                 newcid = cid + 1;
26810a96aa3bSJed Brown               } else {
26820a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
26830a96aa3bSJed Brown 
26849566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetTreeParent(refTree,point,&parent,NULL));
26850a96aa3bSJed Brown                 if (parent == point) {
26860a96aa3bSJed Brown                   newcid = -1;
26870a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
26880a96aa3bSJed Brown                   newcid = point;
26890a96aa3bSJed Brown                 } else {
26900a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
26910a96aa3bSJed Brown 
26920a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
26930a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
26949566063dSJacob Faibussowitsch                       PetscCall(DMPlexGetCellType(refTree, parent, &rct));
26950a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
26960a96aa3bSJed Brown                       break;
26970a96aa3bSJed Brown                     }
26980a96aa3bSJed Brown                   }
269908401ef6SPierre Jolivet                   PetscCheck(rcl < P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Couldn't find parent in root closure");
27009566063dSJacob Faibussowitsch                   PetscCall(DMPlexReferenceTreeGetChildSymmetry(refTree,parent,parentOrnt,ornt,point,DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]),NULL,&newcid));
27010a96aa3bSJed Brown                 }
27020a96aa3bSJed Brown               }
27030a96aa3bSJed Brown               if (newcid >= 0) {
27040a96aa3bSJed Brown 
27050a96aa3bSJed Brown                 if (canonical) {
27069566063dSJacob Faibussowitsch                   PetscCall(DMLabelGetValue(canonical,newcid,&newcid));
27070a96aa3bSJed Brown                 }
27080a96aa3bSJed Brown                 proposedCids[cl] = newcid;
27090a96aa3bSJed Brown               }
27100a96aa3bSJed Brown             }
27119566063dSJacob Faibussowitsch             PetscCall(DMPlexRestoreTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure));
27120a96aa3bSJed Brown           }
27130a96aa3bSJed Brown           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {{quadCoarse->x,quadCoarse->y,
27140a96aa3bSJed Brown #if defined(P4_TO_P8)
27150a96aa3bSJed Brown                                                        quadCoarse->z
27160a96aa3bSJed Brown #endif
27170a96aa3bSJed Brown                                                       },{0}};
27180a96aa3bSJed Brown           p4est_qcoord_t fineBound[2][P4EST_DIM] = {{quad->x,quad->y,
27190a96aa3bSJed Brown #if defined(P4_TO_P8)
27200a96aa3bSJed Brown                                                      quad->z
27210a96aa3bSJed Brown #endif
27220a96aa3bSJed Brown                                                     },{0}};
27230a96aa3bSJed Brown           PetscInt       j;
27240a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
27250a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
27260a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j]   + P4EST_QUADRANT_LEN(quad->level);
27270a96aa3bSJed Brown           }
27280a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
27290a96aa3bSJed Brown             PetscInt    l, p;
27300a96aa3bSJed Brown             PetscSFNode q;
27310a96aa3bSJed Brown 
27320a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
27330a96aa3bSJed Brown             if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
27340a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
27350a96aa3bSJed Brown               l = 0;
27360a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
27370a96aa3bSJed Brown               PetscInt face = PetscFaceToP4estFace[j - 1];
27380a96aa3bSJed Brown               PetscInt direction = face / 2;
27390a96aa3bSJed Brown               PetscInt coarseFace = -1;
27400a96aa3bSJed Brown 
27410a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
27420a96aa3bSJed Brown                 coarseFace = face;
27430a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27440a96aa3bSJed Brown               } else {
27450a96aa3bSJed Brown                 l = 0;
27460a96aa3bSJed Brown               }
27470a96aa3bSJed Brown #if defined(P4_TO_P8)
27480a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
27490a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
27500a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
27510a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
27520a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
27530a96aa3bSJed Brown               PetscInt  minDir     = PetscMin((direction + 1) % 3,(direction + 2) % 3);
27540a96aa3bSJed Brown               PetscInt  maxDir     = PetscMax((direction + 1) % 3,(direction + 2) % 3);
27550a96aa3bSJed Brown               PetscBool dirTest[2];
27560a96aa3bSJed Brown 
27570a96aa3bSJed Brown               dirTest[0] = (PetscBool) (coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
27580a96aa3bSJed Brown               dirTest[1] = (PetscBool) (coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
27590a96aa3bSJed Brown 
27600a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
27610a96aa3bSJed Brown                 coarseEdge = edge;
27620a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
27630a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
27640a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
27650a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27660a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
27670a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
27680a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27690a96aa3bSJed Brown               } else {
27700a96aa3bSJed Brown                 l = 0;
27710a96aa3bSJed Brown               }
27720a96aa3bSJed Brown #endif
27730a96aa3bSJed Brown             } else {
27740a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
27750a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
27760a96aa3bSJed Brown               PetscInt  m;
27770a96aa3bSJed Brown               PetscInt  numMatch     = 0;
27780a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
27790a96aa3bSJed Brown #if defined(P4_TO_P8)
27800a96aa3bSJed Brown               PetscInt coarseEdge = -1;
27810a96aa3bSJed Brown #endif
27820a96aa3bSJed Brown 
27830a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
27840a96aa3bSJed Brown                 dirTest[m] = (PetscBool) (coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
27850a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
27860a96aa3bSJed Brown               }
27870a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
27880a96aa3bSJed Brown                 coarseVertex = vertex;
27890a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
27900a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
27910a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
27920a96aa3bSJed Brown                   if (dirTest[m]) {
27930a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
27940a96aa3bSJed Brown                     break;
27950a96aa3bSJed Brown                   }
27960a96aa3bSJed Brown                 }
27970a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
27980a96aa3bSJed Brown #if defined(P4_TO_P8)
27990a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
28000a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
28010a96aa3bSJed Brown                   if (!dirTest[m]) {
28020a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
28030a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
28040a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1,otherDir2);
28050a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1,otherDir2);
28060a96aa3bSJed Brown 
28070a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
28080a96aa3bSJed Brown                     break;
28090a96aa3bSJed Brown                   }
28100a96aa3bSJed Brown                 }
28110a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
28120a96aa3bSJed Brown #endif
28130a96aa3bSJed Brown               } else { /* volume */
28140a96aa3bSJed Brown                 l = 0;
28150a96aa3bSJed Brown               }
28160a96aa3bSJed Brown             }
28170a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
28180a96aa3bSJed Brown             if (l > rootType[p-pStartF]) {
28190a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
28200a96aa3bSJed Brown                 if (transferIdent) {
28210a96aa3bSJed Brown                   roots[p-pStartF] = q;
28220a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
28230a96aa3bSJed Brown                   if (formCids) cids[p-pStartF] = -1;
28240a96aa3bSJed Brown                 }
28250a96aa3bSJed Brown               } else {
28260a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
28270a96aa3bSJed Brown 
28280a96aa3bSJed Brown                 roots[p-pStartF] = q;
28290a96aa3bSJed Brown                 rootType[p-pStartF] = l;
28300a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
28310a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
28320a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
28330a96aa3bSJed Brown                   PetscInt parent;
28340a96aa3bSJed Brown 
28359566063dSJacob Faibussowitsch                   PetscCall(DMPlexGetTreeParent(plexF,thisp,&parent,NULL));
28360a96aa3bSJed Brown                   if (parent == thisp) break;
28370a96aa3bSJed Brown 
28380a96aa3bSJed Brown                   roots[parent-pStartF] = q;
28390a96aa3bSJed Brown                   rootType[parent-pStartF] = PETSC_MAX_INT;
28400a96aa3bSJed Brown                   if (formCids) cids[parent-pStartF] = -1;
28410a96aa3bSJed Brown                   thisp = parent;
28420a96aa3bSJed Brown                 }
28430a96aa3bSJed Brown               }
28440a96aa3bSJed Brown             }
28450a96aa3bSJed Brown           }
28460a96aa3bSJed Brown         }
28470a96aa3bSJed Brown       }
28480a96aa3bSJed Brown     }
28490a96aa3bSJed Brown 
28500a96aa3bSJed 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 */
28510a96aa3bSJed Brown     if (size > 1) {
28520a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
28530a96aa3bSJed Brown 
28549566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&rootTypeCopy));
28559566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(rootTypeCopy,rootType,pEndF-pStartF));
28569566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX));
28579566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX));
28589566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE));
28599566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE));
28600a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28610a96aa3bSJed 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 */
28620a96aa3bSJed Brown           roots[p-pStartF].rank  = -1;
28630a96aa3bSJed Brown           roots[p-pStartF].index = -1;
28640a96aa3bSJed Brown         }
28650a96aa3bSJed Brown         if (formCids && rootTypeCopy[p-pStartF] == PETSC_MAX_INT) {
28660a96aa3bSJed Brown           cids[p-pStartF] = -1; /* we have found an antecedent that is the same: no child id */
28670a96aa3bSJed Brown         }
28680a96aa3bSJed Brown       }
28699566063dSJacob Faibussowitsch       PetscCall(PetscFree(rootTypeCopy));
28709566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,nodeType,roots,roots,sfNodeReduce));
28719566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,nodeType,roots,roots,sfNodeReduce));
28729566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,nodeType,roots,roots,MPI_REPLACE));
28739566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,nodeType,roots,roots,MPI_REPLACE));
28740a96aa3bSJed Brown     }
28759566063dSJacob Faibussowitsch     PetscCall(PetscFree(rootType));
28760a96aa3bSJed Brown 
28770a96aa3bSJed Brown     {
28780a96aa3bSJed Brown       PetscInt    numRoots;
28790a96aa3bSJed Brown       PetscInt    numLeaves;
28800a96aa3bSJed Brown       PetscInt    *leaves;
28810a96aa3bSJed Brown       PetscSFNode *iremote;
28820a96aa3bSJed Brown       /* count leaves */
28830a96aa3bSJed Brown 
28840a96aa3bSJed Brown       numRoots = pEndC - pStartC;
28850a96aa3bSJed Brown 
28860a96aa3bSJed Brown       numLeaves = 0;
28870a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28880a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) numLeaves++;
28890a96aa3bSJed Brown       }
28909566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves,&leaves));
28919566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(numLeaves,&iremote));
28920a96aa3bSJed Brown       numLeaves = 0;
28930a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
28940a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) {
28950a96aa3bSJed Brown           leaves[numLeaves]  = p-pStartF;
28960a96aa3bSJed Brown           iremote[numLeaves] = roots[p-pStartF];
28970a96aa3bSJed Brown           numLeaves++;
28980a96aa3bSJed Brown         }
28990a96aa3bSJed Brown       }
29009566063dSJacob Faibussowitsch       PetscCall(PetscFree(roots));
29019566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm,sf));
29020a96aa3bSJed Brown       if (numLeaves == (pEndF-pStartF)) {
29039566063dSJacob Faibussowitsch         PetscCall(PetscFree(leaves));
29049566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
29050a96aa3bSJed Brown       } else {
29069566063dSJacob Faibussowitsch         PetscCall(PetscSFSetGraph(*sf,numRoots,numLeaves,leaves,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER));
29070a96aa3bSJed Brown       }
29080a96aa3bSJed Brown     }
29090a96aa3bSJed Brown     if (formCids) {
29100a96aa3bSJed Brown       PetscSF  pointSF;
29110a96aa3bSJed Brown       PetscInt child;
29120a96aa3bSJed Brown 
29139566063dSJacob Faibussowitsch       PetscCall(DMPlexGetReferenceTree(plexF,&refTree));
29149566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(plexF,&pointSF));
29159566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,cids,cids,MPIU_MAX));
29169566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,cids,cids,MPIU_MAX));
29170a96aa3bSJed Brown       if (childIds) *childIds = cids;
29180a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) {
29199566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]));
29200a96aa3bSJed Brown       }
29219566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure));
29220a96aa3bSJed Brown     }
29230a96aa3bSJed Brown   }
29240a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
29259566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
29260a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
29270a96aa3bSJed Brown     if (!childIds) {
29280a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
29290a96aa3bSJed Brown     } else {
29309566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&pforestC->pointSelfToAdaptCids));
29319566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestC->pointSelfToAdaptCids,cids,pEndF-pStartF));
29320a96aa3bSJed Brown     }
29330a96aa3bSJed Brown   } else if (saveInFine) {
29349566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)*sf));
29350a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
29360a96aa3bSJed Brown     if (!childIds) {
29370a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
29380a96aa3bSJed Brown     } else {
29399566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&pforestF->pointAdaptToSelfCids));
29409566063dSJacob Faibussowitsch       PetscCall(PetscArraycpy(pforestF->pointAdaptToSelfCids,cids,pEndF-pStartF));
29410a96aa3bSJed Brown     }
29420a96aa3bSJed Brown   }
29439566063dSJacob Faibussowitsch   PetscCall(PetscFree2(treeQuads,treeQuadCounts));
29449566063dSJacob Faibussowitsch   PetscCall(PetscFree(coverQuads));
29459566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsC));
29469566063dSJacob Faibussowitsch   PetscCall(PetscFree(closurePointsF));
29479566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeClosureType));
29489566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Op_free(&sfNodeReduce));
29499566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Type_free(&nodeType));
29500a96aa3bSJed Brown   PetscFunctionReturn(0);
29510a96aa3bSJed Brown }
29520a96aa3bSJed Brown 
29530a96aa3bSJed Brown /* children are sf leaves of parents */
29540a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
29550a96aa3bSJed Brown {
29560a96aa3bSJed Brown   MPI_Comm          comm;
2957d70f29a3SPierre Jolivet   PetscMPIInt       rank;
29580a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
29590a96aa3bSJed Brown   DM                plexC, plexF;
29600a96aa3bSJed Brown   PetscInt          pStartC, pEndC, pStartF, pEndF;
29610a96aa3bSJed Brown   PetscSF           pointTransferSF;
29620a96aa3bSJed Brown   PetscBool         allOnes = PETSC_TRUE;
29630a96aa3bSJed Brown 
29640a96aa3bSJed Brown   PetscFunctionBegin;
29650a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
29660a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
296708401ef6SPierre Jolivet   PetscCheck(pforestC->topo == pforestF->topo,PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
29680a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
29699566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(comm,&rank));
29700a96aa3bSJed Brown 
29710a96aa3bSJed Brown   {
29720a96aa3bSJed Brown     PetscInt i;
29730a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
29740a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
29750a96aa3bSJed Brown         allOnes = PETSC_FALSE;
29760a96aa3bSJed Brown         break;
29770a96aa3bSJed Brown       }
29780a96aa3bSJed Brown     }
29790a96aa3bSJed Brown   }
29809566063dSJacob Faibussowitsch   PetscCall(DMPforestGetTransferSF_Point(coarse,fine,&pointTransferSF,transferIdent,childIds));
29810a96aa3bSJed Brown   if (allOnes) {
29820a96aa3bSJed Brown     *sf = pointTransferSF;
29830a96aa3bSJed Brown     PetscFunctionReturn(0);
29840a96aa3bSJed Brown   }
29850a96aa3bSJed Brown 
29869566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(fine,&plexF));
29879566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexF,&pStartF,&pEndF));
29889566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(coarse,&plexC));
29899566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plexC,&pStartC,&pEndC));
29900a96aa3bSJed Brown   {
29910a96aa3bSJed Brown     PetscInt          numRoots;
29920a96aa3bSJed Brown     PetscInt          numLeaves;
29930a96aa3bSJed Brown     const PetscInt    *leaves;
29940a96aa3bSJed Brown     const PetscSFNode *iremote;
29950a96aa3bSJed Brown     PetscInt          d;
29960a96aa3bSJed Brown     PetscSection      leafSection, rootSection;
29970a96aa3bSJed Brown     /* count leaves */
29980a96aa3bSJed Brown 
29999566063dSJacob Faibussowitsch     PetscCall(PetscSFGetGraph(pointTransferSF,&numRoots,&numLeaves,&leaves,&iremote));
30009566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&rootSection));
30019566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&leafSection));
30029566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(rootSection,pStartC,pEndC));
30039566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(leafSection,pStartF,pEndF));
30040a96aa3bSJed Brown 
30050a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
30060a96aa3bSJed Brown       PetscInt startC, endC, e;
30070a96aa3bSJed Brown 
30089566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexC,P4EST_DIM-d,&startC,&endC));
30090a96aa3bSJed Brown       for (e = startC; e < endC; e++) {
30109566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(rootSection,e,dofPerDim[d]));
30110a96aa3bSJed Brown       }
30120a96aa3bSJed Brown     }
30130a96aa3bSJed Brown 
30140a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
30150a96aa3bSJed Brown       PetscInt startF, endF, e;
30160a96aa3bSJed Brown 
30179566063dSJacob Faibussowitsch       PetscCall(DMPlexGetSimplexOrBoxCells(plexF,P4EST_DIM-d,&startF,&endF));
30180a96aa3bSJed Brown       for (e = startF; e < endF; e++) {
30199566063dSJacob Faibussowitsch         PetscCall(PetscSectionSetDof(leafSection,e,dofPerDim[d]));
30200a96aa3bSJed Brown       }
30210a96aa3bSJed Brown     }
30220a96aa3bSJed Brown 
30239566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(rootSection));
30249566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(leafSection));
30250a96aa3bSJed Brown     {
30260a96aa3bSJed Brown       PetscInt    nroots, nleaves;
30270a96aa3bSJed Brown       PetscInt    *mine, i, p;
30280a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
30290a96aa3bSJed Brown       PetscSFNode *remote;
30300a96aa3bSJed Brown 
30319566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndF-pStartF,&offsets));
30329566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(pEndC-pStartC,&offsetsRoot));
30330a96aa3bSJed Brown       for (p = pStartC; p < pEndC; p++) {
30349566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(rootSection,p,&offsetsRoot[p-pStartC]));
30350a96aa3bSJed Brown       }
30369566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE));
30379566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE));
30389566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetStorageSize(rootSection,&nroots));
30390a96aa3bSJed Brown       nleaves = 0;
30400a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
30410a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
30420a96aa3bSJed Brown         PetscInt dof;
30430a96aa3bSJed Brown 
30449566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection,leaf,&dof));
30450a96aa3bSJed Brown         nleaves += dof;
30460a96aa3bSJed Brown       }
30479566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&mine));
30489566063dSJacob Faibussowitsch       PetscCall(PetscMalloc1(nleaves,&remote));
30490a96aa3bSJed Brown       nleaves = 0;
30500a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
30510a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
30520a96aa3bSJed Brown         PetscInt dof;
30530a96aa3bSJed Brown         PetscInt off, j;
30540a96aa3bSJed Brown 
30559566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetDof(leafSection,leaf,&dof));
30569566063dSJacob Faibussowitsch         PetscCall(PetscSectionGetOffset(leafSection,leaf,&off));
30570a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
30580a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
30590a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
30600a96aa3bSJed Brown           mine[nleaves++]       = off + j;
30610a96aa3bSJed Brown         }
30620a96aa3bSJed Brown       }
30639566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsetsRoot));
30649566063dSJacob Faibussowitsch       PetscCall(PetscFree(offsets));
30659566063dSJacob Faibussowitsch       PetscCall(PetscSFCreate(comm,sf));
30669566063dSJacob Faibussowitsch       PetscCall(PetscSFSetGraph(*sf,nroots,nleaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
30670a96aa3bSJed Brown     }
30689566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&leafSection));
30699566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&rootSection));
30709566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointTransferSF));
30710a96aa3bSJed Brown   }
30720a96aa3bSJed Brown   PetscFunctionReturn(0);
30730a96aa3bSJed Brown }
30740a96aa3bSJed Brown 
30750a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA)
30760a96aa3bSJed Brown {
30770a96aa3bSJed Brown   DM             adaptA, adaptB;
30780a96aa3bSJed Brown   DMAdaptFlag    purpose;
30790a96aa3bSJed Brown 
30800a96aa3bSJed Brown   PetscFunctionBegin;
30819566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmA,&adaptA));
30829566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmB,&adaptB));
30830a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
30840a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
30859566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmA,&purpose));
30860a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
30879566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30880a96aa3bSJed Brown       PetscFunctionReturn(0);
30890a96aa3bSJed Brown     }
30900a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
30919566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityPurpose(dmB,&purpose));
30920a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
30939566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB));
30940a96aa3bSJed Brown       PetscFunctionReturn(0);
30950a96aa3bSJed Brown     }
30960a96aa3bSJed Brown   }
30970a96aa3bSJed Brown   if (sfAtoB) {
30989566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmA,dmB,dofPerDim,sfAtoB,PETSC_TRUE,NULL));
30990a96aa3bSJed Brown   }
31000a96aa3bSJed Brown   if (sfBtoA) {
31019566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmB,dmA,dofPerDim,sfBtoA,(PetscBool) (sfAtoB == NULL),NULL));
31020a96aa3bSJed Brown   }
31030a96aa3bSJed Brown   PetscFunctionReturn(0);
31040a96aa3bSJed Brown }
31050a96aa3bSJed Brown 
31060a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex)
31070a96aa3bSJed Brown {
31080a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
31090a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
31100a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
31110a96aa3bSJed Brown   PetscInt          cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
31120a96aa3bSJed Brown   PetscInt          pStart, pEnd, pStartBase, pEndBase, p;
31130a96aa3bSJed Brown   DM                base;
31140a96aa3bSJed Brown   PetscInt          *star     = NULL, starSize;
31150a96aa3bSJed Brown   DMLabelLink       next      = dm->labels;
31160a96aa3bSJed Brown   PetscInt          guess     = 0;
31170a96aa3bSJed Brown   p4est_topidx_t    num_trees = pforest->topo->conn->num_trees;
31180a96aa3bSJed Brown 
31190a96aa3bSJed Brown   PetscFunctionBegin;
31200a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
31210a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
31220a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
31239566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
31240a96aa3bSJed Brown   if (!base) {
31250a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
31260a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
31270a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
31280a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t*) p4est->trees->array;
31290a96aa3bSJed Brown       p4est_topidx_t       t, flt = p4est->first_local_tree;
31300a96aa3bSJed Brown       p4est_topidx_t       llt = pforest->forest->last_local_tree;
31310a96aa3bSJed Brown       DMLabel              ghostLabel;
31320a96aa3bSJed Brown       PetscInt             c;
31330a96aa3bSJed Brown 
31349566063dSJacob Faibussowitsch       PetscCall(DMCreateLabel(plex,pforest->ghostName));
31359566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(plex,pforest->ghostName,&ghostLabel));
31360a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
31370a96aa3bSJed Brown         p4est_tree_t     *tree    = &trees[t];
31380a96aa3bSJed Brown         p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
31390a96aa3bSJed Brown         PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
31400a96aa3bSJed Brown         PetscInt         q;
31410a96aa3bSJed Brown 
31420a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
31430a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
31440a96aa3bSJed Brown           PetscInt         f;
31450a96aa3bSJed Brown 
31460a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
31470a96aa3bSJed Brown             p4est_quadrant_t neigh;
31480a96aa3bSJed Brown             int              isOutside;
31490a96aa3bSJed Brown 
31500a96aa3bSJed Brown             PetscStackCallP4est(p4est_quadrant_face_neighbor,(quad,f,&neigh));
31510a96aa3bSJed Brown             PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&neigh));
31520a96aa3bSJed Brown             if (isOutside) {
31530a96aa3bSJed Brown               p4est_topidx_t nt;
31540a96aa3bSJed Brown               PetscInt       nf;
31550a96aa3bSJed Brown 
31560a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
31570a96aa3bSJed Brown               nf = (PetscInt) conn->tree_to_face[t * P4EST_FACES + f];
31580a96aa3bSJed Brown               nf = nf % P4EST_FACES;
31590a96aa3bSJed Brown               if (nt == t && nf == f) {
31600a96aa3bSJed Brown                 PetscInt       plexF = P4estFaceToPetscFace[f];
31610a96aa3bSJed Brown                 const PetscInt *cone;
31620a96aa3bSJed Brown 
31639566063dSJacob Faibussowitsch                 PetscCall(DMPlexGetCone(plex,c,&cone));
31649566063dSJacob Faibussowitsch                 PetscCall(DMLabelSetValue(ghostLabel,cone[plexF],plexF+1));
31650a96aa3bSJed Brown               }
31660a96aa3bSJed Brown             }
31670a96aa3bSJed Brown           }
31680a96aa3bSJed Brown         }
31690a96aa3bSJed Brown       }
31700a96aa3bSJed Brown     }
31710a96aa3bSJed Brown     PetscFunctionReturn(0);
31720a96aa3bSJed Brown   }
31739566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,0,&cStartBase,&cEndBase));
31749566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,1,&fStartBase,&fEndBase));
31759566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(base,P4EST_DIM-1,&eStartBase,&eEndBase));
31769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase));
31770a96aa3bSJed Brown 
31789566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,0,&cStart,&cEnd));
31799566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,1,&fStart,&fEnd));
31809566063dSJacob Faibussowitsch   PetscCall(DMPlexGetSimplexOrBoxCells(plex,P4EST_DIM-1,&eStart,&eEnd));
31819566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex,0,&vStart,&vEnd));
31820a96aa3bSJed Brown 
31839566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex,&pStart,&pEnd));
31849566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(base,&pStartBase,&pEndBase));
31850a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
31860a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
31870a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
31880a96aa3bSJed Brown   while (next) {
31890a96aa3bSJed Brown     DMLabel   baseLabel;
31900a96aa3bSJed Brown     DMLabel   label = next->label;
31910a96aa3bSJed Brown     PetscBool isDepth, isCellType, isGhost, isVTK, isSpmap;
31920a96aa3bSJed Brown     const char *name;
31930a96aa3bSJed Brown 
31949566063dSJacob Faibussowitsch     PetscCall(PetscObjectGetName((PetscObject) label, &name));
31959566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"depth",&isDepth));
31960a96aa3bSJed Brown     if (isDepth) {
31970a96aa3bSJed Brown       next = next->next;
31980a96aa3bSJed Brown       continue;
31990a96aa3bSJed Brown     }
32009566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"celltype",&isCellType));
32010a96aa3bSJed Brown     if (isCellType) {
32020a96aa3bSJed Brown       next = next->next;
32030a96aa3bSJed Brown       continue;
32040a96aa3bSJed Brown     }
32059566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"ghost",&isGhost));
32060a96aa3bSJed Brown     if (isGhost) {
32070a96aa3bSJed Brown       next = next->next;
32080a96aa3bSJed Brown       continue;
32090a96aa3bSJed Brown     }
32109566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"vtk",&isVTK));
32110a96aa3bSJed Brown     if (isVTK) {
32120a96aa3bSJed Brown       next = next->next;
32130a96aa3bSJed Brown       continue;
32140a96aa3bSJed Brown     }
32159566063dSJacob Faibussowitsch     PetscCall(PetscStrcmp(name,"_forest_base_subpoint_map",&isSpmap));
32160a96aa3bSJed Brown     if (!isSpmap) {
32179566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(base,name,&baseLabel));
32180a96aa3bSJed Brown       if (!baseLabel) {
32190a96aa3bSJed Brown         next = next->next;
32200a96aa3bSJed Brown         continue;
32210a96aa3bSJed Brown       }
32229566063dSJacob Faibussowitsch       PetscCall(DMLabelCreateIndex(baseLabel,pStartBase,pEndBase));
32230a96aa3bSJed Brown     } else baseLabel = NULL;
32240a96aa3bSJed Brown 
32250a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
32260a96aa3bSJed Brown       PetscInt         s, c = -1, l;
32270a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
32280a96aa3bSJed Brown       p4est_quadrant_t * ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
32290a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t*) pforest->forest->trees->array;
32300a96aa3bSJed Brown       p4est_quadrant_t * q;
32310a96aa3bSJed Brown       PetscInt         t, val;
32320a96aa3bSJed Brown       PetscBool        zerosupportpoint = PETSC_FALSE;
32330a96aa3bSJed Brown 
32349566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
32350a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
32360a96aa3bSJed Brown         PetscInt point = star[2*s];
32370a96aa3bSJed Brown 
32380a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
32399566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTransitiveClosure(plex,point,PETSC_TRUE,&closureSize,&closure));
32400a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
32410a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
32420a96aa3bSJed Brown             do { /* check parents of q */
32430a96aa3bSJed Brown               q = qParent;
32440a96aa3bSJed Brown               if (q == p) {
32450a96aa3bSJed Brown                 c = point;
32460a96aa3bSJed Brown                 break;
32470a96aa3bSJed Brown               }
32489566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex,q,&qParent,NULL));
32490a96aa3bSJed Brown             } while (qParent != q);
32500a96aa3bSJed Brown             if (c != -1) break;
32519566063dSJacob Faibussowitsch             PetscCall(DMPlexGetTreeParent(plex,pp,&pParent,NULL));
32520a96aa3bSJed Brown             q = closure[2 * l];
32530a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
32540a96aa3bSJed Brown               pp = pParent;
32550a96aa3bSJed Brown               if (pp == q) {
32560a96aa3bSJed Brown                 c = point;
32570a96aa3bSJed Brown                 break;
32580a96aa3bSJed Brown               }
32599566063dSJacob Faibussowitsch               PetscCall(DMPlexGetTreeParent(plex,pp,&pParent,NULL));
32600a96aa3bSJed Brown             }
32610a96aa3bSJed Brown             if (c != -1) break;
32620a96aa3bSJed Brown           }
32639566063dSJacob Faibussowitsch           PetscCall(DMPlexRestoreTransitiveClosure(plex,point,PETSC_TRUE,NULL,&closure));
32640a96aa3bSJed Brown           if (l < closureSize) break;
32650a96aa3bSJed Brown         } else {
32660a96aa3bSJed Brown           PetscInt supportSize;
32670a96aa3bSJed Brown 
32689566063dSJacob Faibussowitsch           PetscCall(DMPlexGetSupportSize(plex,point,&supportSize));
32690a96aa3bSJed Brown           zerosupportpoint = (PetscBool) (zerosupportpoint || !supportSize);
32700a96aa3bSJed Brown         }
32710a96aa3bSJed Brown       }
32720a96aa3bSJed Brown       if (c < 0) {
32730a96aa3bSJed Brown         const char* prefix;
32740a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
32750a96aa3bSJed Brown 
32769566063dSJacob Faibussowitsch         PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix));
32779566063dSJacob Faibussowitsch         PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_forest_print_label_error",&print,NULL));
32780a96aa3bSJed Brown         if (print) {
32790a96aa3bSJed Brown           PetscInt i;
32800a96aa3bSJed Brown 
328163a3b9bcSJacob 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));
328263a3b9bcSJacob 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]));
32830a96aa3bSJed Brown         }
32849566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star));
32850a96aa3bSJed Brown         if (zerosupportpoint) continue;
328663a3b9bcSJacob 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");
32870a96aa3bSJed Brown       }
32889566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star));
32890a96aa3bSJed Brown 
32900a96aa3bSJed Brown       if (c < cLocalStart) {
32910a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
32920a96aa3bSJed Brown         q = &(ghosts[c]);
32930a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
32940a96aa3bSJed Brown       } else if (c < cLocalEnd) {
32950a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
32960a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
32970a96aa3bSJed Brown 
32980a96aa3bSJed Brown         c -= cLocalStart;
32990a96aa3bSJed Brown 
33000a96aa3bSJed Brown         do {
33010a96aa3bSJed Brown           p4est_tree_t *tree;
33020a96aa3bSJed Brown 
33031dca8a05SBarry Smith           PetscCheck(guess >= lo && guess < num_trees && lo < hi,PETSC_COMM_SELF,PETSC_ERR_PLIB,"failed binary search");
33040a96aa3bSJed Brown           tree = &trees[guess];
33050a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
33060a96aa3bSJed Brown             hi = guess;
33070a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt) tree->quadrants.elem_count) {
33080a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt) tree->quadrants_offset];
33090a96aa3bSJed Brown             t = guess;
33100a96aa3bSJed Brown             break;
33110a96aa3bSJed Brown           } else {
33120a96aa3bSJed Brown             lo = guess + 1;
33130a96aa3bSJed Brown           }
33140a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
33150a96aa3bSJed Brown         } while (1);
33160a96aa3bSJed Brown       } else {
33170a96aa3bSJed Brown         /* get from the end of the ghost layer */
33180a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
33190a96aa3bSJed Brown 
33200a96aa3bSJed Brown         q = &(ghosts[c]);
33210a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
33220a96aa3bSJed Brown       }
33230a96aa3bSJed Brown 
33240a96aa3bSJed Brown       if (l == 0) { /* cell */
33250a96aa3bSJed Brown         if (baseLabel) {
33269566063dSJacob Faibussowitsch           PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33270a96aa3bSJed Brown         } else {
33280a96aa3bSJed Brown           val  = t+cStartBase;
33290a96aa3bSJed Brown         }
33309566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label,p,val));
33310a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
33320a96aa3bSJed Brown         p4est_quadrant_t nq;
33330a96aa3bSJed Brown         int              isInside;
33340a96aa3bSJed Brown 
33350a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
33360a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_face_neighbor,(q,l,&nq));
33370a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
33380a96aa3bSJed Brown         if (isInside) {
33390a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
33400a96aa3bSJed Brown           if (baseLabel) {
33419566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33420a96aa3bSJed Brown           } else {
33430a96aa3bSJed Brown             val  = t+cStartBase;
33440a96aa3bSJed Brown           }
33459566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33460a96aa3bSJed Brown         } else {
33470a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
33480a96aa3bSJed Brown 
33490a96aa3bSJed Brown           if (baseLabel) {
33509566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
33510a96aa3bSJed Brown           } else {
33520a96aa3bSJed Brown             val  = f+fStartBase;
33530a96aa3bSJed Brown           }
33549566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33550a96aa3bSJed Brown         }
33560a96aa3bSJed Brown #if defined(P4_TO_P8)
33570a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
33580a96aa3bSJed Brown         p4est_quadrant_t nq;
33590a96aa3bSJed Brown         int              isInside;
33600a96aa3bSJed Brown 
33610a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
33620a96aa3bSJed Brown         PetscStackCallP4est(p8est_quadrant_edge_neighbor,(q,l,&nq));
33630a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
33640a96aa3bSJed Brown         if (isInside) {
33650a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
33660a96aa3bSJed Brown           if (baseLabel) {
33679566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
33680a96aa3bSJed Brown           } else {
33690a96aa3bSJed Brown             val  = t+cStartBase;
33700a96aa3bSJed Brown           }
33719566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
33720a96aa3bSJed Brown         } else {
33730a96aa3bSJed Brown           int isOutsideFace;
33740a96aa3bSJed Brown 
33750a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutsideFace,p4est_quadrant_is_outside_face,(&nq));
33760a96aa3bSJed Brown           if (isOutsideFace) {
33770a96aa3bSJed Brown             PetscInt f;
33780a96aa3bSJed Brown 
33790a96aa3bSJed Brown             if (nq.x < 0) {
33800a96aa3bSJed Brown               f = 0;
33810a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
33820a96aa3bSJed Brown               f = 1;
33830a96aa3bSJed Brown             } else if (nq.y < 0) {
33840a96aa3bSJed Brown               f = 2;
33850a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
33860a96aa3bSJed Brown               f = 3;
33870a96aa3bSJed Brown             } else if (nq.z < 0) {
33880a96aa3bSJed Brown               f = 4;
33890a96aa3bSJed Brown             } else {
33900a96aa3bSJed Brown               f = 5;
33910a96aa3bSJed Brown             }
33920a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
33930a96aa3bSJed Brown             if (baseLabel) {
33949566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
33950a96aa3bSJed Brown             } else {
33960a96aa3bSJed Brown               val  = f+fStartBase;
33970a96aa3bSJed Brown             }
33989566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
33990a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
34000a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
34010a96aa3bSJed Brown 
34020a96aa3bSJed Brown             if (baseLabel) {
34039566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,e+eStartBase,&val));
34040a96aa3bSJed Brown             } else {
34050a96aa3bSJed Brown               val  = e+eStartBase;
34060a96aa3bSJed Brown             }
34079566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
34080a96aa3bSJed Brown           }
34090a96aa3bSJed Brown         }
34100a96aa3bSJed Brown #endif
34110a96aa3bSJed Brown       } else { /* vertex */
34120a96aa3bSJed Brown         p4est_quadrant_t nq;
34130a96aa3bSJed Brown         int              isInside;
34140a96aa3bSJed Brown 
34150a96aa3bSJed Brown #if defined(P4_TO_P8)
34160a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
34170a96aa3bSJed Brown #else
34180a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
34190a96aa3bSJed Brown #endif
34200a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_corner_neighbor,(q,l,&nq));
34210a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
34220a96aa3bSJed Brown         if (isInside) {
34230a96aa3bSJed Brown           if (baseLabel) {
34249566063dSJacob Faibussowitsch             PetscCall(DMLabelGetValue(baseLabel,t+cStartBase,&val));
34250a96aa3bSJed Brown           } else {
34260a96aa3bSJed Brown             val  = t+cStartBase;
34270a96aa3bSJed Brown           }
34289566063dSJacob Faibussowitsch           PetscCall(DMLabelSetValue(label,p,val));
34290a96aa3bSJed Brown         } else {
34300a96aa3bSJed Brown           int isOutside;
34310a96aa3bSJed Brown 
34320a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&nq));
34330a96aa3bSJed Brown           if (isOutside) {
34340a96aa3bSJed Brown             PetscInt f = -1;
34350a96aa3bSJed Brown 
34360a96aa3bSJed Brown             if (nq.x < 0) {
34370a96aa3bSJed Brown               f = 0;
34380a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
34390a96aa3bSJed Brown               f = 1;
34400a96aa3bSJed Brown             } else if (nq.y < 0) {
34410a96aa3bSJed Brown               f = 2;
34420a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
34430a96aa3bSJed Brown               f = 3;
34440a96aa3bSJed Brown #if defined(P4_TO_P8)
34450a96aa3bSJed Brown             } else if (nq.z < 0) {
34460a96aa3bSJed Brown               f = 4;
34470a96aa3bSJed Brown             } else {
34480a96aa3bSJed Brown               f = 5;
34490a96aa3bSJed Brown #endif
34500a96aa3bSJed Brown             }
34510a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
34520a96aa3bSJed Brown             if (baseLabel) {
34539566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,f+fStartBase,&val));
34540a96aa3bSJed Brown             } else {
34550a96aa3bSJed Brown               val  = f+fStartBase;
34560a96aa3bSJed Brown             }
34579566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
34580a96aa3bSJed Brown             continue;
34590a96aa3bSJed Brown           }
34600a96aa3bSJed Brown #if defined(P4_TO_P8)
34610a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p8est_quadrant_is_outside_edge,(&nq));
34620a96aa3bSJed Brown           if (isOutside) {
34630a96aa3bSJed Brown             /* outside edge */
34640a96aa3bSJed Brown             PetscInt e = -1;
34650a96aa3bSJed Brown 
34660a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
34670a96aa3bSJed Brown               if (nq.z < 0) {
34680a96aa3bSJed Brown                 if (nq.y < 0) {
34690a96aa3bSJed Brown                   e = 0;
34700a96aa3bSJed Brown                 } else {
34710a96aa3bSJed Brown                   e = 1;
34720a96aa3bSJed Brown                 }
34730a96aa3bSJed Brown               } else {
34740a96aa3bSJed Brown                 if (nq.y < 0) {
34750a96aa3bSJed Brown                   e = 2;
34760a96aa3bSJed Brown                 } else {
34770a96aa3bSJed Brown                   e = 3;
34780a96aa3bSJed Brown                 }
34790a96aa3bSJed Brown               }
34800a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
34810a96aa3bSJed Brown               if (nq.z < 0) {
34820a96aa3bSJed Brown                 if (nq.x < 0) {
34830a96aa3bSJed Brown                   e = 4;
34840a96aa3bSJed Brown                 } else {
34850a96aa3bSJed Brown                   e = 5;
34860a96aa3bSJed Brown                 }
34870a96aa3bSJed Brown               } else {
34880a96aa3bSJed Brown                 if (nq.x < 0) {
34890a96aa3bSJed Brown                   e = 6;
34900a96aa3bSJed Brown                 } else {
34910a96aa3bSJed Brown                   e = 7;
34920a96aa3bSJed Brown                 }
34930a96aa3bSJed Brown               }
34940a96aa3bSJed Brown             } else {
34950a96aa3bSJed Brown               if (nq.y < 0) {
34960a96aa3bSJed Brown                 if (nq.x < 0) {
34970a96aa3bSJed Brown                   e = 8;
34980a96aa3bSJed Brown                 } else {
34990a96aa3bSJed Brown                   e = 9;
35000a96aa3bSJed Brown                 }
35010a96aa3bSJed Brown               } else {
35020a96aa3bSJed Brown                 if (nq.x < 0) {
35030a96aa3bSJed Brown                   e = 10;
35040a96aa3bSJed Brown                 } else {
35050a96aa3bSJed Brown                   e = 11;
35060a96aa3bSJed Brown                 }
35070a96aa3bSJed Brown               }
35080a96aa3bSJed Brown             }
35090a96aa3bSJed Brown 
35100a96aa3bSJed Brown             e    = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
35110a96aa3bSJed Brown             if (baseLabel) {
35129566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,e+eStartBase,&val));
35130a96aa3bSJed Brown             } else {
35140a96aa3bSJed Brown               val  = e+eStartBase;
35150a96aa3bSJed Brown             }
35169566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
35170a96aa3bSJed Brown             continue;
35180a96aa3bSJed Brown           }
35190a96aa3bSJed Brown #endif
35200a96aa3bSJed Brown           {
35210a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
35220a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
35230a96aa3bSJed Brown 
35240a96aa3bSJed Brown             if (baseLabel) {
35259566063dSJacob Faibussowitsch               PetscCall(DMLabelGetValue(baseLabel,v+vStartBase,&val));
35260a96aa3bSJed Brown             } else {
35270a96aa3bSJed Brown               val  = v+vStartBase;
35280a96aa3bSJed Brown             }
35299566063dSJacob Faibussowitsch             PetscCall(DMLabelSetValue(label,p,val));
35300a96aa3bSJed Brown           }
35310a96aa3bSJed Brown         }
35320a96aa3bSJed Brown       }
35330a96aa3bSJed Brown     }
35340a96aa3bSJed Brown     next = next->next;
35350a96aa3bSJed Brown   }
35360a96aa3bSJed Brown   PetscFunctionReturn(0);
35370a96aa3bSJed Brown }
35380a96aa3bSJed Brown 
35390a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex)
35400a96aa3bSJed Brown {
35410a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
35420a96aa3bSJed Brown   DM                adapt;
35430a96aa3bSJed Brown 
35440a96aa3bSJed Brown   PetscFunctionBegin;
35450a96aa3bSJed Brown   if (pforest->labelsFinalized) PetscFunctionReturn(0);
35460a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
35479566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dm,&adapt));
35480a96aa3bSJed Brown   if (!adapt) {
35490a96aa3bSJed Brown     /* Initialize labels from the base dm */
35509566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsInitialize(dm,plex));
35510a96aa3bSJed Brown   } else {
35520a96aa3bSJed Brown     PetscInt    dofPerDim[4]={1, 1, 1, 1};
35530a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
35540a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
35550a96aa3bSJed Brown     PetscInt    *values, *adaptValues;
35560a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
35570a96aa3bSJed Brown     DMLabel     adaptLabel;
35580a96aa3bSJed Brown     DM          adaptPlex;
35590a96aa3bSJed Brown 
35609566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdaptivityLabel(dm,&adaptLabel));
35619566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(adapt,&adaptPlex));
35629566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF(adapt,dm,dofPerDim,&transferForward,&transferBackward));
35639566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex,&pStart,&pEnd));
35649566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(adaptPlex,&pStartA,&pEndA));
35659566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(pEnd-pStart,&values,pEndA-pStartA,&adaptValues));
35669566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex,&pointSF));
35670a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
35680a96aa3bSJed Brown       PetscInt p;
35690a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p-pStartA] = -1;
35700a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++)   values[p-pStart]       = -2;
35710a96aa3bSJed Brown       if (transferForward) {
35729566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
35739566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
35740a96aa3bSJed Brown       }
35750a96aa3bSJed Brown       if (transferBackward) {
35769566063dSJacob Faibussowitsch         PetscCall(PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
35779566063dSJacob Faibussowitsch         PetscCall(PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
35780a96aa3bSJed Brown       }
35790a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
35800a96aa3bSJed Brown         PetscInt q = p, parent;
35810a96aa3bSJed Brown 
35829566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
35830a96aa3bSJed Brown         while (parent != q) {
35840a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
35850a96aa3bSJed Brown           q    = parent;
35869566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
35870a96aa3bSJed Brown         }
35880a96aa3bSJed Brown       }
35899566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX));
35909566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX));
35919566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE));
35929566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE));
35930a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
359463a3b9bcSJacob Faibussowitsch         PetscCheck(values[p-pStart] != -2,PETSC_COMM_SELF,PETSC_ERR_PLIB,"uncovered point %" PetscInt_FMT,p);
35950a96aa3bSJed Brown       }
35960a96aa3bSJed Brown     }
35970a96aa3bSJed Brown     while (next) {
35980a96aa3bSJed Brown       DMLabel    nextLabel = next->label;
35990a96aa3bSJed Brown       const char *name;
36000a96aa3bSJed Brown       PetscBool  isDepth, isCellType, isGhost, isVTK;
36010a96aa3bSJed Brown       DMLabel    label;
36020a96aa3bSJed Brown       PetscInt   p;
36030a96aa3bSJed Brown 
36049566063dSJacob Faibussowitsch       PetscCall(PetscObjectGetName((PetscObject) nextLabel, &name));
36059566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"depth",&isDepth));
36060a96aa3bSJed Brown       if (isDepth) {
36070a96aa3bSJed Brown         next = next->next;
36080a96aa3bSJed Brown         continue;
36090a96aa3bSJed Brown       }
36109566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"celltype",&isCellType));
36110a96aa3bSJed Brown       if (isCellType) {
36120a96aa3bSJed Brown         next = next->next;
36130a96aa3bSJed Brown         continue;
36140a96aa3bSJed Brown       }
36159566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"ghost",&isGhost));
36160a96aa3bSJed Brown       if (isGhost) {
36170a96aa3bSJed Brown         next = next->next;
36180a96aa3bSJed Brown         continue;
36190a96aa3bSJed Brown       }
36209566063dSJacob Faibussowitsch       PetscCall(PetscStrcmp(name,"vtk",&isVTK));
36210a96aa3bSJed Brown       if (isVTK) {
36220a96aa3bSJed Brown         next = next->next;
36230a96aa3bSJed Brown         continue;
36240a96aa3bSJed Brown       }
36250a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
36260a96aa3bSJed Brown         next = next->next;
36270a96aa3bSJed Brown         continue;
36280a96aa3bSJed Brown       }
36290a96aa3bSJed Brown       /* label was created earlier */
36309566063dSJacob Faibussowitsch       PetscCall(DMGetLabel(dm,name,&label));
36310a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) {
36329566063dSJacob Faibussowitsch         PetscCall(DMLabelGetValue(nextLabel,p,&adaptValues[p]));
36330a96aa3bSJed Brown       }
36340a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
36350a96aa3bSJed Brown 
36360a96aa3bSJed Brown       if (transferForward) {
36379566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
36380a96aa3bSJed Brown       }
36390a96aa3bSJed Brown       if (transferBackward) {
36409566063dSJacob Faibussowitsch         PetscCall(PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
36410a96aa3bSJed Brown       }
36420a96aa3bSJed Brown       if (transferForward) {
36439566063dSJacob Faibussowitsch         PetscCall(PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE));
36440a96aa3bSJed Brown       }
36450a96aa3bSJed Brown       if (transferBackward) {
36469566063dSJacob Faibussowitsch         PetscCall(PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX));
36470a96aa3bSJed Brown       }
36480a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
36490a96aa3bSJed Brown         PetscInt q = p, parent;
36500a96aa3bSJed Brown 
36519566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
36520a96aa3bSJed Brown         while (parent != q) {
36530a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
36540a96aa3bSJed Brown           q    = parent;
36559566063dSJacob Faibussowitsch           PetscCall(DMPlexGetTreeParent(plex,q,&parent,NULL));
36560a96aa3bSJed Brown         }
36570a96aa3bSJed Brown       }
36589566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX));
36599566063dSJacob Faibussowitsch       PetscCall(PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX));
36609566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE));
36619566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE));
36620a96aa3bSJed Brown 
36630a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
36649566063dSJacob Faibussowitsch         PetscCall(DMLabelSetValue(label,p,values[p]));
36650a96aa3bSJed Brown       }
36660a96aa3bSJed Brown       next = next->next;
36670a96aa3bSJed Brown     }
36689566063dSJacob Faibussowitsch     PetscCall(PetscFree2(values,adaptValues));
36699566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferForward));
36709566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferBackward));
36710a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
36720a96aa3bSJed Brown   }
36730a96aa3bSJed Brown   PetscFunctionReturn(0);
36740a96aa3bSJed Brown }
36750a96aa3bSJed Brown 
36760a96aa3bSJed 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)
36770a96aa3bSJed Brown {
36780a96aa3bSJed Brown   PetscInt       closureSize, c, coordStart, coordEnd, coordDim;
36790a96aa3bSJed Brown   PetscInt       *closure = NULL;
36800a96aa3bSJed Brown   PetscSection   coordSec;
36810a96aa3bSJed Brown 
36820a96aa3bSJed Brown   PetscFunctionBegin;
36839566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex,&coordSec));
36849566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetChart(coordSec,&coordStart,&coordEnd));
36859566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(plex,&coordDim));
36869566063dSJacob Faibussowitsch   PetscCall(DMPlexGetTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure));
36870a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
36880a96aa3bSJed Brown     PetscInt point = closure[2 * c];
36890a96aa3bSJed Brown 
36900a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
36910a96aa3bSJed Brown       PetscInt dof, off;
36920a96aa3bSJed Brown       PetscInt nCoords, i;
36939566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec,point,&dof));
369408401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
36950a96aa3bSJed Brown       nCoords = dof / coordDim;
36969566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec,point,&off));
36970a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
36980a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
36990a96aa3bSJed Brown         double      coordP4est[3]       = {0.};
37000a96aa3bSJed Brown         double      coordP4estMapped[3] = {0.};
37010a96aa3bSJed Brown         PetscInt    j;
37020a96aa3bSJed Brown         PetscReal   treeCoords[P4EST_CHILDREN][3] = {{0.}};
37030a96aa3bSJed Brown         PetscReal   eta[3]                        = {0.};
37040a96aa3bSJed Brown         PetscInt    numRounds                     = 10;
37050a96aa3bSJed Brown         PetscReal   coordGuess[3]                 = {0.};
37060a96aa3bSJed Brown 
37070a96aa3bSJed Brown         eta[0] = (PetscReal) q->x / (PetscReal) P4EST_ROOT_LEN;
37080a96aa3bSJed Brown         eta[1] = (PetscReal) q->y / (PetscReal) P4EST_ROOT_LEN;
37090a96aa3bSJed Brown #if defined(P4_TO_P8)
37100a96aa3bSJed Brown         eta[2] = (PetscReal) q->z / (PetscReal) P4EST_ROOT_LEN;
37110a96aa3bSJed Brown #endif
37120a96aa3bSJed Brown 
37130a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
37140a96aa3bSJed Brown           PetscInt k;
37150a96aa3bSJed Brown 
37160a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
37170a96aa3bSJed Brown         }
37180a96aa3bSJed Brown 
37190a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
37200a96aa3bSJed Brown           PetscInt  k;
37210a96aa3bSJed Brown           PetscReal prod = 1.;
37220a96aa3bSJed Brown 
37230a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
37240a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
37250a96aa3bSJed Brown         }
37260a96aa3bSJed Brown 
37270a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
37280a96aa3bSJed Brown           PetscInt dir;
37290a96aa3bSJed Brown 
37300a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
37310a96aa3bSJed Brown             PetscInt  k;
37320a96aa3bSJed Brown             PetscReal diff[3];
37330a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
37340a96aa3bSJed Brown             PetscReal rhs, scale, update;
37350a96aa3bSJed Brown 
37360a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
37370a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
37380a96aa3bSJed Brown               PetscInt  l;
37390a96aa3bSJed Brown               PetscReal prod = 1.;
37400a96aa3bSJed Brown 
37410a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
37420a96aa3bSJed Brown                 if (l == dir) {
37430a96aa3bSJed Brown                   prod *= (k & (1 << l)) ?  1. : -1.;
37440a96aa3bSJed Brown                 } else {
37450a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
37460a96aa3bSJed Brown                 }
37470a96aa3bSJed Brown               }
37480a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
37490a96aa3bSJed Brown             }
37500a96aa3bSJed Brown             rhs   = 0.;
37510a96aa3bSJed Brown             scale = 0;
37520a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
37530a96aa3bSJed Brown               rhs   += diff[k] * dXdeta[k];
37540a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
37550a96aa3bSJed Brown             }
37560a96aa3bSJed Brown             update    = rhs / scale;
37570a96aa3bSJed Brown             eta[dir] += update;
37580a96aa3bSJed Brown             eta[dir]  = PetscMin(eta[dir],1.);
37590a96aa3bSJed Brown             eta[dir]  = PetscMax(eta[dir],0.);
37600a96aa3bSJed Brown 
37610a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
37620a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
37630a96aa3bSJed Brown               PetscInt  l;
37640a96aa3bSJed Brown               PetscReal prod = 1.;
37650a96aa3bSJed Brown 
37660a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
37670a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
37680a96aa3bSJed Brown             }
37690a96aa3bSJed Brown           }
37700a96aa3bSJed Brown         }
37710a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double) eta[j];
37720a96aa3bSJed Brown 
37730a96aa3bSJed Brown         if (geom) {
37740a96aa3bSJed Brown           (geom->X)(geom,t,coordP4est,coordP4estMapped);
37750a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
37760a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not coded");
37770a96aa3bSJed Brown       }
37780a96aa3bSJed Brown     }
37790a96aa3bSJed Brown   }
37809566063dSJacob Faibussowitsch   PetscCall(DMPlexRestoreTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure));
37810a96aa3bSJed Brown   PetscFunctionReturn(0);
37820a96aa3bSJed Brown }
37830a96aa3bSJed Brown 
37840a96aa3bSJed Brown static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex)
37850a96aa3bSJed Brown {
37860a96aa3bSJed Brown   DM_Forest         *forest;
37870a96aa3bSJed Brown   DM_Forest_pforest *pforest;
37880a96aa3bSJed Brown   p4est_geometry_t  *geom;
37890a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd;
37900a96aa3bSJed Brown   Vec               coordLocalVec;
37910a96aa3bSJed Brown   PetscScalar       *coords;
37920a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
37930a96aa3bSJed Brown   p4est_tree_t      *trees;
37940a96aa3bSJed Brown   PetscErrorCode    (*map)(DM,PetscInt, PetscInt, const PetscReal [], PetscReal [], void*);
37950a96aa3bSJed Brown   void              *mapCtx;
37960a96aa3bSJed Brown 
37970a96aa3bSJed Brown   PetscFunctionBegin;
37980a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
37990a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
38000a96aa3bSJed Brown   geom    = pforest->topo->geom;
38019566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx));
38020a96aa3bSJed Brown   if (!geom && !map) PetscFunctionReturn(0);
38039566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex,&coordLocalVec));
38049566063dSJacob Faibussowitsch   PetscCall(VecGetArray(coordLocalVec,&coords));
38050a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
38060a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
38070a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
38080a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
38090a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
38100a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
38110a96aa3bSJed Brown     PetscSection coordSec;
38120a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
38130a96aa3bSJed Brown     DM           base;
38140a96aa3bSJed Brown 
38159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
38169566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
38170a96aa3bSJed Brown     cEnd          = cEndInterior < 0 ? cEnd : cEndInterior;
38189566063dSJacob Faibussowitsch     PetscCall(DMForestGetBaseDM(dm,&base));
38199566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateSection(plex,&coordSec));
38209566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetChart(coordSec,&coordStart,&coordEnd));
38219566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(plex,&coordDim));
38220a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim,3);
38230a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
38240a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
38250a96aa3bSJed Brown       PetscInt dof, off, cell = -1, coarsePoint = -1;
38260a96aa3bSJed Brown       PetscInt nCoords, i;
38279566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetDof(coordSec,p,&dof));
382808401ef6SPierre Jolivet       PetscCheck(dof % coordDim == 0,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
38290a96aa3bSJed Brown       nCoords = dof / coordDim;
38309566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(coordSec,p,&off));
38319566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
38320a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
38330a96aa3bSJed Brown         PetscInt point = star[2 * i];
38340a96aa3bSJed Brown 
38350a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
38360a96aa3bSJed Brown           cell = point;
38370a96aa3bSJed Brown           break;
38380a96aa3bSJed Brown         }
38390a96aa3bSJed Brown       }
38409566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star));
38410a96aa3bSJed Brown       if (cell >= 0) {
38420a96aa3bSJed Brown         if (cell < cLocalStart) {
38430a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38440a96aa3bSJed Brown 
38450a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
38460a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
38470a96aa3bSJed Brown           cell -= cLocalStart;
38480a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
38490a96aa3bSJed Brown             p4est_tree_t *tree = &(trees[t]);
38500a96aa3bSJed Brown 
38510a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t) cell < tree->quadrants_offset + tree->quadrants.elem_count) {
38520a96aa3bSJed Brown               coarsePoint = t;
38530a96aa3bSJed Brown               break;
38540a96aa3bSJed Brown             }
38550a96aa3bSJed Brown           }
38560a96aa3bSJed Brown         } else {
38570a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38580a96aa3bSJed Brown 
38590a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
38600a96aa3bSJed Brown         }
38610a96aa3bSJed Brown       }
38620a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
38630a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
38640a96aa3bSJed Brown         PetscReal   coordP4est[3]       = {0.};
38650a96aa3bSJed Brown         PetscReal   coordP4estMapped[3] = {0.};
38660a96aa3bSJed Brown         PetscInt    j;
38670a96aa3bSJed Brown 
38680a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
38699566063dSJacob Faibussowitsch         PetscCall((map)(base,coarsePoint,p4estCoordDim,coordP4est,coordP4estMapped,mapCtx));
38700a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
38710a96aa3bSJed Brown       }
38720a96aa3bSJed Brown     }
38730a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
38740a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
38750a96aa3bSJed Brown 
38769566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
38779566063dSJacob Faibussowitsch     PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
38780a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
38790a96aa3bSJed Brown     if (cLocalStart > 0) {
38800a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
38810a96aa3bSJed Brown       PetscInt         count;
38820a96aa3bSJed Brown 
38830a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
38840a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
38850a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
38860a96aa3bSJed Brown 
38879566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count,quad,t,pforest->topo->conn,coords));
38880a96aa3bSJed Brown       }
38890a96aa3bSJed Brown     }
38900a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
38910a96aa3bSJed Brown       p4est_tree_t     *tree    = &(trees[t]);
38920a96aa3bSJed Brown       PetscInt         offset   = cLocalStart + tree->quadrants_offset, i;
38930a96aa3bSJed Brown       PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
38940a96aa3bSJed Brown       p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
38950a96aa3bSJed Brown 
38960a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
38970a96aa3bSJed Brown         PetscInt count = i + offset;
38980a96aa3bSJed Brown 
38999566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count,&quads[i],t,pforest->topo->conn,coords));
39000a96aa3bSJed Brown       }
39010a96aa3bSJed Brown     }
39020a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
39030a96aa3bSJed Brown       p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
39040a96aa3bSJed Brown       PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
39050a96aa3bSJed Brown       PetscInt         count;
39060a96aa3bSJed Brown 
39070a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
39080a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
39090a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
39100a96aa3bSJed Brown 
39119566063dSJacob Faibussowitsch         PetscCall(DMPforestMapCoordinates_Cell(plex,geom,count + cLocalEnd,quad,t,pforest->topo->conn,coords));
39120a96aa3bSJed Brown       }
39130a96aa3bSJed Brown     }
39140a96aa3bSJed Brown   }
39159566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(coordLocalVec,&coords));
39160a96aa3bSJed Brown   PetscFunctionReturn(0);
39170a96aa3bSJed Brown }
39180a96aa3bSJed Brown 
39190a96aa3bSJed Brown static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
39200a96aa3bSJed Brown {
39210a96aa3bSJed Brown   DM_Forest         *forest;
39220a96aa3bSJed Brown   DM_Forest_pforest *pforest;
39230a96aa3bSJed Brown   DM                base;
39240a96aa3bSJed Brown   Vec               coordinates, cVec;
39250a96aa3bSJed Brown   PetscSection      oldSection, baseSection = NULL, newSection;
39260a96aa3bSJed Brown   const PetscScalar *coords;
39270a96aa3bSJed Brown   PetscScalar       *coords2;
39280a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, coarsePoint;
39290a96aa3bSJed Brown   PetscInt          cDim, newStart, newEnd, dof, cdof = -1;
39300a96aa3bSJed Brown   PetscInt          v, vStart, vEnd, cp, cStart, cEnd, cEndInterior, *coarsePoints;
39310a96aa3bSJed Brown   PetscInt          *localize, overlap;
39320a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
39330a96aa3bSJed Brown   p4est_tree_t      *trees;
39340a96aa3bSJed Brown   PetscBool         isper, baseLocalized = PETSC_FALSE;
39350a96aa3bSJed Brown 
39360a96aa3bSJed Brown   PetscFunctionBegin;
39379566063dSJacob Faibussowitsch   PetscCall(DMGetPeriodicity(dm,&isper,NULL,NULL,NULL));
39380a96aa3bSJed Brown   if (!isper) PetscFunctionReturn(0);
39390a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
39409566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDim(dm, &cDim));
39410a96aa3bSJed Brown   cdof = P4EST_CHILDREN*cDim;
39429566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
39430a96aa3bSJed Brown   if (base) {
39449566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinatesLocalized(base,&baseLocalized));
39450a96aa3bSJed Brown   }
39460a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
39479566063dSJacob Faibussowitsch   PetscCall(DMPlexGetChart(plex, &newStart, &newEnd));
39480a96aa3bSJed Brown 
39499566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
39509566063dSJacob Faibussowitsch   PetscCall(PetscCalloc1(overlap ? newEnd - newStart : 0,&localize));
39510a96aa3bSJed Brown 
39529566063dSJacob Faibussowitsch   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &newSection));
39539566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetNumFields(newSection, 1));
39549566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim));
39559566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetChart(newSection, newStart, newEnd));
39560a96aa3bSJed Brown 
39579566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateSection(plex, &oldSection));
39589566063dSJacob Faibussowitsch   if (base) PetscCall(DMGetCoordinateSection(base, &baseSection));
39599566063dSJacob Faibussowitsch   PetscCall(DMPlexGetDepthStratum(plex,0,&vStart,&vEnd));
39600a96aa3bSJed Brown   for (v = vStart; v < vEnd; ++v) {
39619566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(oldSection, v, &dof));
39629566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetDof(newSection, v, dof));
39639566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetFieldDof(newSection, v, 0, dof));
39640a96aa3bSJed Brown     if (overlap) localize[v] = dof;
39650a96aa3bSJed Brown   }
39660a96aa3bSJed Brown 
39670a96aa3bSJed Brown   forest      = (DM_Forest*) dm->data;
39680a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
39690a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
39700a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
39710a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
39720a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
39730a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
39740a96aa3bSJed Brown 
39750a96aa3bSJed Brown   cp = 0;
39769566063dSJacob Faibussowitsch   PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd));
39779566063dSJacob Faibussowitsch   PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL));
39780a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
39799566063dSJacob Faibussowitsch   PetscCall(PetscMalloc1(cEnd-cStart,&coarsePoints));
39800a96aa3bSJed Brown   if (cLocalStart > 0) {
39810a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
39820a96aa3bSJed Brown     PetscInt         count;
39830a96aa3bSJed Brown 
39840a96aa3bSJed Brown     for (count = 0; count < cLocalStart; count++) {
39850a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count];
39860a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
39870a96aa3bSJed Brown 
39889566063dSJacob Faibussowitsch       if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
39899566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(newSection, count, cdof));
39909566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(newSection, count, 0, cdof));
39910a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
39920a96aa3bSJed Brown       if (overlap) localize[count] = cdof;
39930a96aa3bSJed Brown     }
39940a96aa3bSJed Brown   }
39950a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
39960a96aa3bSJed Brown     p4est_tree_t *tree    = &(trees[t]);
39970a96aa3bSJed Brown     PetscInt     offset   = cLocalStart + tree->quadrants_offset;
39980a96aa3bSJed Brown     PetscInt     numQuads = (PetscInt) tree->quadrants.elem_count;
39990a96aa3bSJed Brown     PetscInt     i;
40000a96aa3bSJed Brown 
40010a96aa3bSJed Brown     if (!numQuads) continue;
40020a96aa3bSJed Brown     coarsePoint = t;
40039566063dSJacob Faibussowitsch     if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
40040a96aa3bSJed Brown     for (i = 0; i < numQuads; i++) {
40050a96aa3bSJed Brown       PetscInt newCell = i + offset;
40060a96aa3bSJed Brown 
40079566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(newSection, newCell, cdof));
40089566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
40090a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
40100a96aa3bSJed Brown       if (overlap) localize[newCell] = cdof;
40110a96aa3bSJed Brown     }
40120a96aa3bSJed Brown   }
40130a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
40140a96aa3bSJed Brown     p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
40150a96aa3bSJed Brown     PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
40160a96aa3bSJed Brown     PetscInt         count;
40170a96aa3bSJed Brown 
40180a96aa3bSJed Brown     for (count = 0; count < numGhosts - cLocalStart; count++) {
40190a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
40200a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
40210a96aa3bSJed Brown       PetscInt newCell = count + cLocalEnd;
40220a96aa3bSJed Brown 
40239566063dSJacob Faibussowitsch       if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
40249566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(newSection, newCell, cdof));
40259566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
40260a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
40270a96aa3bSJed Brown       if (overlap) localize[newCell] = cdof;
40280a96aa3bSJed Brown     }
40290a96aa3bSJed Brown   }
40301dca8a05SBarry Smith   PetscCheck(cp == cEnd - cStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT,cp,cEnd-cStart);
40310a96aa3bSJed Brown 
40320a96aa3bSJed Brown   if (base) { /* we need to localize on all the cells in the star of the coarse cell vertices */
40330a96aa3bSJed Brown     PetscInt *closure = NULL, closureSize;
40340a96aa3bSJed Brown     PetscInt p, i, c, vStartBase, vEndBase, cStartBase, cEndBase;
40350a96aa3bSJed Brown 
40369566063dSJacob Faibussowitsch     PetscCall(DMPlexGetHeightStratum(base,0,&cStartBase,&cEndBase));
40379566063dSJacob Faibussowitsch     PetscCall(DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase));
40380a96aa3bSJed Brown     for (p = cStart; p < cEnd; p++) {
40390a96aa3bSJed Brown       coarsePoint = coarsePoints[p-cStart];
40400a96aa3bSJed Brown       if (coarsePoint < 0) continue;
40419566063dSJacob Faibussowitsch       if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof));
40429566063dSJacob Faibussowitsch       PetscCall(DMPlexGetTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure));
40430a96aa3bSJed Brown       for (c = 0; c < closureSize; c++) {
40440a96aa3bSJed Brown         PetscInt *star = NULL, starSize;
40450a96aa3bSJed Brown         PetscInt j, v = closure[2 * c];
40460a96aa3bSJed Brown 
40470a96aa3bSJed Brown         if (v < vStartBase || v > vEndBase) continue;
40489566063dSJacob Faibussowitsch         PetscCall(DMPlexGetTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star));
40490a96aa3bSJed Brown         for (j = 0; j < starSize; j++) {
40500a96aa3bSJed Brown           PetscInt cell = star[2 * j];
40510a96aa3bSJed Brown 
40520a96aa3bSJed Brown           if (cStartBase <= cell && cell < cEndBase) {
40530a96aa3bSJed Brown             p4est_tree_t *tree;
40540a96aa3bSJed Brown             PetscInt     offset,numQuads;
40550a96aa3bSJed Brown 
40560a96aa3bSJed Brown             if (cell < flt || cell > llt) continue;
40570a96aa3bSJed Brown             tree     = &(trees[cell]);
40580a96aa3bSJed Brown             offset   = cLocalStart + tree->quadrants_offset;
40590a96aa3bSJed Brown             numQuads = (PetscInt) tree->quadrants.elem_count;
40600a96aa3bSJed Brown             for (i = 0; i < numQuads; i++) {
40610a96aa3bSJed Brown               PetscInt newCell = i + offset;
40620a96aa3bSJed Brown 
40639566063dSJacob Faibussowitsch               PetscCall(PetscSectionSetDof(newSection, newCell, cdof));
40649566063dSJacob Faibussowitsch               PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof));
40650a96aa3bSJed Brown               if (overlap) localize[newCell] = cdof;
40660a96aa3bSJed Brown             }
40670a96aa3bSJed Brown           }
40680a96aa3bSJed Brown         }
40699566063dSJacob Faibussowitsch         PetscCall(DMPlexRestoreTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star));
40700a96aa3bSJed Brown       }
40719566063dSJacob Faibussowitsch       PetscCall(DMPlexRestoreTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure));
40720a96aa3bSJed Brown     }
40730a96aa3bSJed Brown   }
40749566063dSJacob Faibussowitsch   PetscCall(PetscFree(coarsePoints));
40750a96aa3bSJed Brown 
40760a96aa3bSJed Brown   /* final consensus with overlap */
40770a96aa3bSJed Brown   if (overlap) {
40780a96aa3bSJed Brown     PetscSF  sf;
40790a96aa3bSJed Brown     PetscInt *localizeGlobal;
40800a96aa3bSJed Brown 
40819566063dSJacob Faibussowitsch     PetscCall(DMGetPointSF(plex,&sf));
40829566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(newEnd-newStart,&localizeGlobal));
40830a96aa3bSJed Brown     for (v = newStart; v < newEnd; v++) localizeGlobal[v - newStart] = localize[v - newStart];
40849566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE));
40859566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE));
40860a96aa3bSJed Brown     for (v = newStart; v < newEnd; v++) {
40879566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(newSection, v, localizeGlobal[v-newStart]));
40889566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetFieldDof(newSection, v, 0, localizeGlobal[v-newStart]));
40890a96aa3bSJed Brown     }
40909566063dSJacob Faibussowitsch     PetscCall(PetscFree(localizeGlobal));
40910a96aa3bSJed Brown   }
40929566063dSJacob Faibussowitsch   PetscCall(PetscFree(localize));
40939566063dSJacob Faibussowitsch   PetscCall(PetscSectionSetUp(newSection));
40949566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)oldSection));
40959566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinateSection(plex, cDim, newSection));
40969566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetStorageSize(newSection, &v));
40979566063dSJacob Faibussowitsch   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
40989566063dSJacob Faibussowitsch   PetscCall(PetscObjectSetName((PetscObject)cVec,"coordinates"));
40999566063dSJacob Faibussowitsch   PetscCall(VecSetBlockSize(cVec, cDim));
41009566063dSJacob Faibussowitsch   PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE));
41019566063dSJacob Faibussowitsch   PetscCall(VecSetType(cVec, VECSTANDARD));
41029566063dSJacob Faibussowitsch   PetscCall(VecSet(cVec, PETSC_MIN_REAL));
41030a96aa3bSJed Brown 
41040a96aa3bSJed Brown   /* Copy over vertex coordinates */
41059566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinatesLocal(plex, &coordinates));
410628b400f6SJacob Faibussowitsch   PetscCheck(coordinates,PetscObjectComm((PetscObject)plex),PETSC_ERR_SUP,"Missing local coordinates vector");
41079566063dSJacob Faibussowitsch   PetscCall(VecGetArray(cVec, &coords2));
41089566063dSJacob Faibussowitsch   PetscCall(VecGetArrayRead(coordinates, &coords));
41090a96aa3bSJed Brown   for (v = vStart; v < vEnd; ++v) {
41100a96aa3bSJed Brown     PetscInt d, off,off2;
41110a96aa3bSJed Brown 
41129566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetDof(oldSection, v, &dof));
41139566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(oldSection, v, &off));
41149566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetOffset(newSection, v, &off2));
41150a96aa3bSJed Brown     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
41160a96aa3bSJed Brown   }
41179566063dSJacob Faibussowitsch   PetscCall(VecRestoreArrayRead(coordinates, &coords));
41180a96aa3bSJed Brown 
41190a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
41200a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
41210a96aa3bSJed Brown     p4est_tree_t     *tree    = &(trees[t]);
41220a96aa3bSJed Brown     const double     *v       = pforest->topo->conn->vertices;
41230a96aa3bSJed Brown     p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
41240a96aa3bSJed Brown     PetscInt         offset   = cLocalStart + tree->quadrants_offset;
41250a96aa3bSJed Brown     PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
41260a96aa3bSJed Brown     p4est_topidx_t   vt[8]    = {0,0,0,0,0,0,0,0};
41270a96aa3bSJed Brown     PetscInt         i,k;
41280a96aa3bSJed Brown 
41290a96aa3bSJed Brown     if (!numQuads) continue;
41300a96aa3bSJed Brown     for (k = 0; k < P4EST_CHILDREN; ++k) {
41310a96aa3bSJed Brown       vt[k] = pforest->topo->conn->tree_to_vertex[t * P4EST_CHILDREN + k];
41320a96aa3bSJed Brown     }
41330a96aa3bSJed Brown 
41340a96aa3bSJed Brown     for (i = 0; i < numQuads; i++) {
41350a96aa3bSJed Brown       p4est_quadrant_t  *quad = &quads[i];
41360a96aa3bSJed Brown       const PetscReal   intsize = 1.0 / P4EST_ROOT_LEN;
41370a96aa3bSJed Brown       PetscReal         h2;
41380a96aa3bSJed Brown       PetscScalar       xyz[3];
41390a96aa3bSJed Brown #ifdef P4_TO_P8
41400a96aa3bSJed Brown       PetscInt          zi;
41410a96aa3bSJed Brown #endif
41420a96aa3bSJed Brown       PetscInt          yi,xi;
41430a96aa3bSJed Brown       PetscInt          off2;
41440a96aa3bSJed Brown       PetscInt          newCell = i + offset;
41450a96aa3bSJed Brown 
41469566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetFieldDof(newSection, newCell, 0, &cdof));
41470a96aa3bSJed Brown       if (!cdof) continue;
41480a96aa3bSJed Brown 
41490a96aa3bSJed Brown       h2   = .5 * intsize * P4EST_QUADRANT_LEN (quad->level);
41500a96aa3bSJed Brown       k    = 0;
41519566063dSJacob Faibussowitsch       PetscCall(PetscSectionGetOffset(newSection, newCell, &off2));
41520a96aa3bSJed Brown #ifdef P4_TO_P8
41530a96aa3bSJed Brown       for (zi = 0; zi < 2; ++zi) {
41540a96aa3bSJed Brown         const PetscReal eta_z = intsize * quad->z + h2 * (1. + (zi * 2 - 1));
41550a96aa3bSJed Brown #else
41560a96aa3bSJed Brown       {
41570a96aa3bSJed Brown         const PetscReal eta_z = 0.0;
41580a96aa3bSJed Brown #endif
41590a96aa3bSJed Brown         for (yi = 0; yi < 2; ++yi) {
41600a96aa3bSJed Brown           const PetscReal eta_y = intsize * quad->y + h2 * (1. + (yi * 2 - 1));
41610a96aa3bSJed Brown           for (xi = 0; xi < 2; ++xi) {
41620a96aa3bSJed Brown             const PetscReal eta_x = intsize * quad->x + h2 * (1. + (xi * 2 - 1));
41630a96aa3bSJed Brown             PetscInt    j;
41640a96aa3bSJed Brown 
41650a96aa3bSJed Brown             for (j = 0; j < 3; ++j) {
41660a96aa3bSJed Brown               xyz[j] = ((1. - eta_z) * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[0] + j] +
41670a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[1] + j]) +
41680a96aa3bSJed Brown                                               eta_y  * ((1. - eta_x) * v[3 * vt[2] + j] +
41690a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[3] + j]))
41700a96aa3bSJed Brown                         +     eta_z  * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[4] + j] +
41710a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[5] + j]) +
41720a96aa3bSJed Brown                                               eta_y  * ((1. - eta_x) * v[3 * vt[6] + j] +
41730a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[7] + j])));
41740a96aa3bSJed Brown             }
41750a96aa3bSJed Brown             for (j = 0; j < cDim; ++j) coords2[off2 + cDim*P4estVertToPetscVert[k] + j] = xyz[j];
41760a96aa3bSJed Brown             ++k;
41770a96aa3bSJed Brown           }
41780a96aa3bSJed Brown         }
41790a96aa3bSJed Brown       }
41800a96aa3bSJed Brown     }
41810a96aa3bSJed Brown   }
41829566063dSJacob Faibussowitsch   PetscCall(VecRestoreArray(cVec, &coords2));
41839566063dSJacob Faibussowitsch   PetscCall(DMSetCoordinatesLocal(plex, cVec));
41849566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&cVec));
41859566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&newSection));
41869566063dSJacob Faibussowitsch   PetscCall(PetscSectionDestroy(&oldSection));
41870a96aa3bSJed Brown   PetscFunctionReturn(0);
41880a96aa3bSJed Brown }
41890a96aa3bSJed Brown 
41900a96aa3bSJed Brown #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
41910a96aa3bSJed Brown static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
41920a96aa3bSJed Brown {
41930a96aa3bSJed Brown   DM_Forest         *forest;
41940a96aa3bSJed Brown   DM_Forest_pforest *pforest;
41950a96aa3bSJed Brown 
41960a96aa3bSJed Brown   PetscFunctionBegin;
41970a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
41980a96aa3bSJed Brown   pforest = (DM_Forest_pforest *) forest->data;
41999566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointAdaptToSelfSF)));
42009566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&(pforest->pointSelfToAdaptSF)));
42019566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
42029566063dSJacob Faibussowitsch   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
42030a96aa3bSJed Brown   PetscFunctionReturn(0);
42040a96aa3bSJed Brown }
42050a96aa3bSJed Brown 
42060a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
42070a96aa3bSJed Brown {
42080a96aa3bSJed Brown   DM_Forest            *forest;
42090a96aa3bSJed Brown   DM_Forest_pforest    *pforest;
42100a96aa3bSJed Brown   DM                   refTree, newPlex, base;
42110a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
42120a96aa3bSJed Brown   MPI_Comm             comm;
42130a96aa3bSJed Brown   PetscBool            isPforest;
42140a96aa3bSJed Brown   PetscInt             dim;
42150a96aa3bSJed Brown   PetscInt             overlap;
42160a96aa3bSJed Brown   p4est_connect_type_t ctype;
42170a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
42180a96aa3bSJed Brown   sc_array_t           *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
42190a96aa3bSJed Brown   PetscSection         parentSection;
42200a96aa3bSJed Brown   PetscSF              pointSF;
42210a96aa3bSJed Brown   size_t               zz, count;
42220a96aa3bSJed Brown   PetscInt             pStart, pEnd;
42230a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
42240a96aa3bSJed Brown 
42250a96aa3bSJed Brown   PetscFunctionBegin;
42260a96aa3bSJed Brown 
42270a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
42280a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
42299566063dSJacob Faibussowitsch   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPFOREST,&isPforest));
423028b400f6SJacob Faibussowitsch   PetscCheck(isPforest,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPFOREST,((PetscObject)dm)->type_name);
42319566063dSJacob Faibussowitsch   PetscCall(DMGetDimension(dm,&dim));
423263a3b9bcSJacob Faibussowitsch   PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim);
42330a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
42340a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
42359566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
42360a96aa3bSJed Brown   if (base) {
42379566063dSJacob Faibussowitsch     PetscCall(DMGetLabel(base,"ghost",&ghostLabelBase));
42380a96aa3bSJed Brown   }
42390a96aa3bSJed Brown   if (!pforest->plex) {
42400a96aa3bSJed Brown     PetscMPIInt size;
42410a96aa3bSJed Brown 
42429566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_size(comm,&size));
42439566063dSJacob Faibussowitsch     PetscCall(DMCreate(comm,&newPlex));
42449566063dSJacob Faibussowitsch     PetscCall(DMSetType(newPlex,DMPLEX));
42459566063dSJacob Faibussowitsch     PetscCall(DMSetMatType(newPlex,dm->mattype));
42460a96aa3bSJed Brown     /* share labels */
42479566063dSJacob Faibussowitsch     PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
42489566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyDimension(dm,&adjDim));
42499566063dSJacob Faibussowitsch     PetscCall(DMForestGetAdjacencyCodimension(dm,&adjCodim));
42509566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDim(dm,&coordDim));
42510a96aa3bSJed Brown     if (adjDim == 0) {
42520a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
42530a96aa3bSJed Brown     } else if (adjCodim == 1) {
42540a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
42550a96aa3bSJed Brown #if defined(P4_TO_P8)
42560a96aa3bSJed Brown     } else if (adjDim == 1) {
42570a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
42580a96aa3bSJed Brown #endif
42590a96aa3bSJed Brown     } else {
426063a3b9bcSJacob Faibussowitsch       SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Invalid adjacency dimension %" PetscInt_FMT,adjDim);
42610a96aa3bSJed Brown     }
426263a3b9bcSJacob 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);
42639566063dSJacob Faibussowitsch     PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
426460667520SVaclav Hapla     PetscCall(DMPlexSetOverlap_Plex(newPlex,NULL,overlap));
42650a96aa3bSJed Brown 
42660a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
42670a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
42680a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
42690a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
42700a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
42710a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
42720a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
42730a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
42740a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
42750a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
42760a96aa3bSJed Brown 
42770a96aa3bSJed 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));
42780a96aa3bSJed Brown 
42790a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt) first_local_quad;
42800a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt) pforest->forest->local_num_quadrants;
42819566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(points_per_dim));
42829566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_sizes));
42839566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cones));
42849566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(cone_orientations));
42859566063dSJacob Faibussowitsch     PetscCall(coords_double_to_PetscScalar(coords, coordDim));
42869566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(children));
42879566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(parents));
42889566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(childids));
42899566063dSJacob Faibussowitsch     PetscCall(locidx_to_PetscInt(leaves));
42909566063dSJacob Faibussowitsch     PetscCall(locidx_pair_to_PetscSFNode(remotes));
42910a96aa3bSJed Brown 
42929566063dSJacob Faibussowitsch     PetscCall(DMSetDimension(newPlex,P4EST_DIM));
42939566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDim(newPlex,coordDim));
42949566063dSJacob Faibussowitsch     PetscCall(DMPlexSetMaxProjectionHeight(newPlex,P4EST_DIM - 1));
42959566063dSJacob 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));
42969566063dSJacob Faibussowitsch     PetscCall(DMPlexConvertOldOrientations_Internal(newPlex));
42979566063dSJacob Faibussowitsch     PetscCall(DMCreateReferenceTree_pforest(comm,&refTree));
42989566063dSJacob Faibussowitsch     PetscCall(DMPlexSetReferenceTree(newPlex,refTree));
42999566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(comm,&parentSection));
43009566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(newPlex,&pStart,&pEnd));
43019566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetChart(parentSection,pStart,pEnd));
43020a96aa3bSJed Brown     count = children->elem_count;
43030a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
43040a96aa3bSJed Brown       PetscInt child = *((PetscInt*) sc_array_index(children,zz));
43050a96aa3bSJed Brown 
43069566063dSJacob Faibussowitsch       PetscCall(PetscSectionSetDof(parentSection,child,1));
43070a96aa3bSJed Brown     }
43089566063dSJacob Faibussowitsch     PetscCall(PetscSectionSetUp(parentSection));
43099566063dSJacob Faibussowitsch     PetscCall(DMPlexSetTree(newPlex,parentSection,(PetscInt*)parents->array,(PetscInt*)childids->array));
43109566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&parentSection));
43119566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(comm,&pointSF));
43120a96aa3bSJed Brown     /*
43130a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
43140a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
43150a96aa3bSJed Brown     */
43169566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(pointSF,pEnd - pStart,(PetscInt)leaves->elem_count,(PetscInt*)leaves->array,PETSC_COPY_VALUES,(PetscSFNode*)remotes->array,PETSC_COPY_VALUES));
43179566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(newPlex,pointSF));
43189566063dSJacob Faibussowitsch     PetscCall(DMSetPointSF(dm,pointSF));
43190a96aa3bSJed Brown     {
43200a96aa3bSJed Brown       DM coordDM;
43210a96aa3bSJed Brown 
43229566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43239566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(coordDM,pointSF));
43240a96aa3bSJed Brown     }
43259566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&pointSF));
43260a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
43270a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
43280a96aa3bSJed Brown     sc_array_destroy (cones);
43290a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
43300a96aa3bSJed Brown     sc_array_destroy (coords);
43310a96aa3bSJed Brown     sc_array_destroy (children);
43320a96aa3bSJed Brown     sc_array_destroy (parents);
43330a96aa3bSJed Brown     sc_array_destroy (childids);
43340a96aa3bSJed Brown     sc_array_destroy (leaves);
43350a96aa3bSJed Brown     sc_array_destroy (remotes);
43360a96aa3bSJed Brown 
43370a96aa3bSJed Brown     {
43380a96aa3bSJed Brown       PetscBool             isper;
43390a96aa3bSJed Brown       const PetscReal      *maxCell, *L;
43400a96aa3bSJed Brown       const DMBoundaryType *bd;
43410a96aa3bSJed Brown 
43429566063dSJacob Faibussowitsch       PetscCall(DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd));
43439566063dSJacob Faibussowitsch       PetscCall(DMSetPeriodicity(newPlex,isper,maxCell,L,bd));
43449566063dSJacob Faibussowitsch       PetscCall(DMPforestLocalizeCoordinates(dm,newPlex));
43450a96aa3bSJed Brown     }
43460a96aa3bSJed Brown 
43470a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
43480a96aa3bSJed Brown       Vec               coordsGlobal, coordsLocal;
43490a96aa3bSJed Brown       const PetscScalar *globalArray;
43500a96aa3bSJed Brown       PetscScalar       *localArray;
43510a96aa3bSJed Brown       PetscSF           coordSF;
43520a96aa3bSJed Brown       DM                coordDM;
43530a96aa3bSJed Brown 
43549566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
43559566063dSJacob Faibussowitsch       PetscCall(DMGetSectionSF(coordDM,&coordSF));
43569566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinates(newPlex, &coordsGlobal));
43579566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal));
43589566063dSJacob Faibussowitsch       PetscCall(VecGetArrayRead(coordsGlobal, &globalArray));
43599566063dSJacob Faibussowitsch       PetscCall(VecGetArray(coordsLocal, &localArray));
43609566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastBegin(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
43619566063dSJacob Faibussowitsch       PetscCall(PetscSFBcastEnd(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
43629566063dSJacob Faibussowitsch       PetscCall(VecRestoreArray(coordsLocal, &localArray));
43639566063dSJacob Faibussowitsch       PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray));
43649566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal));
43650a96aa3bSJed Brown     }
43669566063dSJacob Faibussowitsch     PetscCall(DMPforestMapCoordinates(dm,newPlex));
43670a96aa3bSJed Brown 
43680a96aa3bSJed Brown     pforest->plex = newPlex;
43690a96aa3bSJed Brown 
43700a96aa3bSJed Brown     /* copy labels */
43719566063dSJacob Faibussowitsch     PetscCall(DMPforestLabelsFinalize(dm,newPlex));
43720a96aa3bSJed Brown 
43730a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
43740a96aa3bSJed Brown       PetscInt numAdded;
43750a96aa3bSJed Brown       DM       newPlexGhosted;
43760a96aa3bSJed Brown       void     *ctx;
43770a96aa3bSJed Brown 
43789566063dSJacob Faibussowitsch       PetscCall(DMPlexConstructGhostCells(newPlex,pforest->ghostName,&numAdded,&newPlexGhosted));
43799566063dSJacob Faibussowitsch       PetscCall(DMGetApplicationContext(newPlex,&ctx));
43809566063dSJacob Faibussowitsch       PetscCall(DMSetApplicationContext(newPlexGhosted,ctx));
43810a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
43829566063dSJacob Faibussowitsch       PetscCall(DMGetPointSF(newPlexGhosted,&pointSF));
43839566063dSJacob Faibussowitsch       PetscCall(DMSetPointSF(dm,pointSF));
43849566063dSJacob Faibussowitsch       PetscCall(DMDestroy(&newPlex));
43859566063dSJacob Faibussowitsch       PetscCall(DMPlexSetReferenceTree(newPlexGhosted,refTree));
43869566063dSJacob Faibussowitsch       PetscCall(DMForestClearAdaptivityForest_pforest(dm));
43870a96aa3bSJed Brown       newPlex = newPlexGhosted;
43880a96aa3bSJed Brown 
43890a96aa3bSJed Brown       /* share the labels back */
43909566063dSJacob Faibussowitsch       PetscCall(DMDestroyLabelLinkList_Internal(dm));
43919566063dSJacob Faibussowitsch       PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
43920a96aa3bSJed Brown       pforest->plex = newPlex;
43930a96aa3bSJed Brown     }
43949566063dSJacob Faibussowitsch     PetscCall(DMDestroy(&refTree));
43950a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
43965f80ce2aSJacob Faibussowitsch 
4397d0609cedSBarry Smith       PetscObjectOptionsBegin((PetscObject)newPlex);
43989566063dSJacob Faibussowitsch       PetscCall(DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject,newPlex));
43999566063dSJacob Faibussowitsch       PetscCall(PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)newPlex));
4400d0609cedSBarry Smith       PetscOptionsEnd();
44010a96aa3bSJed Brown     }
44029566063dSJacob Faibussowitsch     PetscCall(DMViewFromOptions(newPlex,NULL,"-dm_p4est_plex_view"));
44030a96aa3bSJed Brown     {
44040a96aa3bSJed Brown       PetscSection coordsSec;
44050a96aa3bSJed Brown       Vec          coords;
44060a96aa3bSJed Brown       PetscInt     cDim;
44070a96aa3bSJed Brown 
44089566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateDim(newPlex,&cDim));
44099566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinateSection(newPlex,&coordsSec));
44109566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinateSection(dm,cDim,coordsSec));
44119566063dSJacob Faibussowitsch       PetscCall(DMGetCoordinatesLocal(newPlex,&coords));
44129566063dSJacob Faibussowitsch       PetscCall(DMSetCoordinatesLocal(dm,coords));
44130a96aa3bSJed Brown     }
44140a96aa3bSJed Brown   }
44150a96aa3bSJed Brown   newPlex = pforest->plex;
44160a96aa3bSJed Brown   if (plex) {
44170a96aa3bSJed Brown     DM coordDM;
44180a96aa3bSJed Brown 
44199566063dSJacob Faibussowitsch     PetscCall(DMClone(newPlex,plex));
44209566063dSJacob Faibussowitsch     PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
44219566063dSJacob Faibussowitsch     PetscCall(DMSetCoordinateDM(*plex,coordDM));
44229566063dSJacob Faibussowitsch     PetscCall(DMShareDiscretization(dm,*plex));
44230a96aa3bSJed Brown   }
44240a96aa3bSJed Brown   PetscFunctionReturn(0);
44250a96aa3bSJed Brown }
44260a96aa3bSJed Brown 
44270a96aa3bSJed Brown static PetscErrorCode DMSetFromOptions_pforest(PetscOptionItems *PetscOptionsObject,DM dm)
44280a96aa3bSJed Brown {
44290a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44300a96aa3bSJed Brown   char              stringBuffer[256];
44310a96aa3bSJed Brown   PetscBool         flg;
44320a96aa3bSJed Brown 
44330a96aa3bSJed Brown   PetscFunctionBegin;
44349566063dSJacob Faibussowitsch   PetscCall(DMSetFromOptions_Forest(PetscOptionsObject,dm));
4435d0609cedSBarry Smith   PetscOptionsHeadBegin(PetscOptionsObject,"DM" P4EST_STRING " options");
44369566063dSJacob Faibussowitsch   PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening","partition forest to allow for coarsening","DMP4estSetPartitionForCoarsening",pforest->partition_for_coarsening,&(pforest->partition_for_coarsening),NULL));
44379566063dSJacob 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));
4438d0609cedSBarry Smith   PetscOptionsHeadEnd();
44390a96aa3bSJed Brown   if (flg) {
44409566063dSJacob Faibussowitsch     PetscCall(PetscFree(pforest->ghostName));
44419566063dSJacob Faibussowitsch     PetscCall(PetscStrallocpy(stringBuffer,&pforest->ghostName));
44420a96aa3bSJed Brown   }
44430a96aa3bSJed Brown   PetscFunctionReturn(0);
44440a96aa3bSJed Brown }
44450a96aa3bSJed Brown 
44460a96aa3bSJed Brown #if !defined(P4_TO_P8)
44470a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
44480a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
44490a96aa3bSJed Brown #else
44500a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
44510a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
44520a96aa3bSJed Brown #endif
44530a96aa3bSJed Brown 
44540a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
44550a96aa3bSJed Brown {
44560a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44570a96aa3bSJed Brown 
44580a96aa3bSJed Brown   PetscFunctionBegin;
44590a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
44600a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44610a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
44620a96aa3bSJed Brown   PetscFunctionReturn(0);
44630a96aa3bSJed Brown }
44640a96aa3bSJed Brown 
44650a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
44660a96aa3bSJed Brown {
44670a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44680a96aa3bSJed Brown 
44690a96aa3bSJed Brown   PetscFunctionBegin;
44700a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
44710a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44720a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
44730a96aa3bSJed Brown   PetscFunctionReturn(0);
44740a96aa3bSJed Brown }
44750a96aa3bSJed Brown 
44760a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM dm,DM *plex)
44770a96aa3bSJed Brown {
44780a96aa3bSJed Brown   DM_Forest_pforest *pforest;
44790a96aa3bSJed Brown 
44800a96aa3bSJed Brown   PetscFunctionBegin;
44810a96aa3bSJed Brown   if (plex) *plex = NULL;
44829566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
44830a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
44840a96aa3bSJed Brown   if (!pforest->plex) {
44859566063dSJacob Faibussowitsch     PetscCall(DMConvert_pforest_plex(dm,DMPLEX,NULL));
44860a96aa3bSJed Brown   }
44879566063dSJacob Faibussowitsch   PetscCall(DMShareDiscretization(dm,pforest->plex));
44880a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
44890a96aa3bSJed Brown   PetscFunctionReturn(0);
44900a96aa3bSJed Brown }
44910a96aa3bSJed Brown 
44920a96aa3bSJed Brown #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
44930a96aa3bSJed Brown static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
44940a96aa3bSJed Brown {
44950a96aa3bSJed Brown   PetscSection   gsc, gsf;
44960a96aa3bSJed Brown   PetscInt       m, n;
44970a96aa3bSJed Brown   DM             cdm;
44980a96aa3bSJed Brown 
44990a96aa3bSJed Brown   PetscFunctionBegin;
45009566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
45019566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
45029566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
45039566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
45040a96aa3bSJed Brown 
45059566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), interpolation));
45069566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
45079566063dSJacob Faibussowitsch   PetscCall(MatSetType(*interpolation, MATAIJ));
45080a96aa3bSJed Brown 
45099566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
451008401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only interpolation from coarse DM for now");
45110a96aa3bSJed Brown 
45120a96aa3bSJed Brown   {
45130a96aa3bSJed Brown     DM       plexF, plexC;
45140a96aa3bSJed Brown     PetscSF  sf;
45150a96aa3bSJed Brown     PetscInt *cids;
45160a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
45170a96aa3bSJed Brown 
45189566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse,&plexC));
45199566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine,&plexF));
45209566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
45219566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
45229566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
45239566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
45249566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
45250a96aa3bSJed Brown   }
45269566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
45270a96aa3bSJed Brown   /* Use naive scaling */
45289566063dSJacob Faibussowitsch   PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
45290a96aa3bSJed Brown   PetscFunctionReturn(0);
45300a96aa3bSJed Brown }
45310a96aa3bSJed Brown 
45320a96aa3bSJed Brown #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
45330a96aa3bSJed Brown static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
45340a96aa3bSJed Brown {
45350a96aa3bSJed Brown   PetscSection   gsc, gsf;
45360a96aa3bSJed Brown   PetscInt       m, n;
45370a96aa3bSJed Brown   DM             cdm;
45380a96aa3bSJed Brown 
45390a96aa3bSJed Brown   PetscFunctionBegin;
45409566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmFine, &gsf));
45419566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n));
45429566063dSJacob Faibussowitsch   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
45439566063dSJacob Faibussowitsch   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m));
45440a96aa3bSJed Brown 
45459566063dSJacob Faibussowitsch   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), injection));
45469566063dSJacob Faibussowitsch   PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
45479566063dSJacob Faibussowitsch   PetscCall(MatSetType(*injection, MATAIJ));
45480a96aa3bSJed Brown 
45499566063dSJacob Faibussowitsch   PetscCall(DMGetCoarseDM(dmFine, &cdm));
455008401ef6SPierre Jolivet   PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only injection to coarse DM for now");
45510a96aa3bSJed Brown 
45520a96aa3bSJed Brown   {
45530a96aa3bSJed Brown     DM       plexF, plexC;
45540a96aa3bSJed Brown     PetscSF  sf;
45550a96aa3bSJed Brown     PetscInt *cids;
45560a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
45570a96aa3bSJed Brown 
45589566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmCoarse,&plexC));
45599566063dSJacob Faibussowitsch     PetscCall(DMPforestGetPlex(dmFine,&plexF));
45609566063dSJacob Faibussowitsch     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
45619566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(sf));
45629566063dSJacob Faibussowitsch     PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
45639566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&sf));
45649566063dSJacob Faibussowitsch     PetscCall(PetscFree(cids));
45650a96aa3bSJed Brown   }
45669566063dSJacob Faibussowitsch   PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
45670a96aa3bSJed Brown   /* Use naive scaling */
45680a96aa3bSJed Brown   PetscFunctionReturn(0);
45690a96aa3bSJed Brown }
45700a96aa3bSJed Brown 
45710a96aa3bSJed Brown #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
45720a96aa3bSJed Brown static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
45730a96aa3bSJed Brown {
45740a96aa3bSJed Brown   DM             dmIn, dmVecIn, base, basec, plex, coarseDM;
45750a96aa3bSJed Brown   DM             *hierarchy;
45760a96aa3bSJed Brown   PetscSF        sfRed = NULL;
45770a96aa3bSJed Brown   PetscDS        ds;
45780a96aa3bSJed Brown   Vec            vecInLocal, vecOutLocal;
45790a96aa3bSJed Brown   DMLabel        subpointMap;
45800a96aa3bSJed Brown   PetscInt       minLevel, mh, n_hi, i;
45810a96aa3bSJed Brown   PetscBool      hiforest, *hierarchy_forest;
45820a96aa3bSJed Brown 
45830a96aa3bSJed Brown   PetscFunctionBegin;
45849566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vecIn,&dmVecIn));
45859566063dSJacob Faibussowitsch   PetscCall(DMGetDS(dmVecIn,&ds));
458628b400f6SJacob Faibussowitsch   PetscCheck(ds,PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Cannot transfer without a PetscDS object");
45870a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
45880a96aa3bSJed Brown     PetscSection section;
45890a96aa3bSJed Brown     PetscInt     Nf;
45900a96aa3bSJed Brown 
45919566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn,&section));
45929566063dSJacob Faibussowitsch     PetscCall(PetscSectionGetNumFields(section,&Nf));
459363a3b9bcSJacob 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);
45940a96aa3bSJed Brown   }
45959566063dSJacob Faibussowitsch   PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
459663a3b9bcSJacob Faibussowitsch   PetscCheck(!minLevel,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)",minLevel);
45979566063dSJacob Faibussowitsch   PetscCall(DMForestGetBaseDM(dm,&base));
459828b400f6SJacob Faibussowitsch   PetscCheck(base,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing base DM");
45990a96aa3bSJed Brown 
46009566063dSJacob Faibussowitsch   PetscCall(VecSet(vecOut,0.0));
46010a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
46029566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
46030a96aa3bSJed Brown   } else {
46040a96aa3bSJed Brown     PetscSection secIn, secInRed;
46050a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
46060a96aa3bSJed Brown 
46079566063dSJacob Faibussowitsch     PetscCall(PetscObjectQuery((PetscObject)base,"_base_migration_sf",(PetscObject*)&sfRed));
460828b400f6SJacob Faibussowitsch     PetscCheck(sfRed,PETSC_COMM_SELF,PETSC_ERR_SUP,"Not the DM set with DMForestSetBaseDM()");
46099566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn),&secInRed));
46109566063dSJacob Faibussowitsch     PetscCall(VecCreate(PETSC_COMM_SELF,&vecInRed));
46119566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(dmVecIn,&secIn));
46129566063dSJacob Faibussowitsch     PetscCall(DMGetLocalVector(dmVecIn,&vecInLocal));
46139566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
46149566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
46159566063dSJacob Faibussowitsch     PetscCall(DMPlexDistributeField(dmVecIn,sfRed,secIn,vecInLocal,secInRed,vecInRed));
46169566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmVecIn,&vecInLocal));
46179566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secInRed));
46180a96aa3bSJed Brown     vecIn = vecInRed;
46190a96aa3bSJed Brown   }
46200a96aa3bSJed Brown 
46210a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
46220a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
46230a96aa3bSJed Brown   hiforest = PETSC_TRUE;
46240a96aa3bSJed Brown 
46250a96aa3bSJed Brown   /* upsweep to the coarsest DM */
46260a96aa3bSJed Brown   n_hi = 0;
46270a96aa3bSJed Brown   coarseDM = dm;
46280a96aa3bSJed Brown   do {
46290a96aa3bSJed Brown     PetscBool isforest;
46300a96aa3bSJed Brown 
46310a96aa3bSJed Brown     dmIn = coarseDM;
46320a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
46339566063dSJacob Faibussowitsch     PetscCall(DMSetUp(dmIn));
46349566063dSJacob Faibussowitsch     PetscCall(DMIsForest(dmIn,&isforest));
463528b400f6SJacob Faibussowitsch     PetscCheck(isforest,PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Cannot currently transfer through a mixed hierarchy! Found DM type %s",((PetscObject)dmIn)->type_name);
46360a96aa3bSJed Brown     coarseDM = NULL;
46370a96aa3bSJed Brown     if (hiforest) {
46389566063dSJacob Faibussowitsch       PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM));
46390a96aa3bSJed Brown     }
46400a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
46410a96aa3bSJed Brown       hiforest = PETSC_FALSE;
46429566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn,&coarseDM));
46430a96aa3bSJed Brown     }
46440a96aa3bSJed Brown     n_hi++;
46450a96aa3bSJed Brown   } while (coarseDM);
46460a96aa3bSJed Brown 
46479566063dSJacob Faibussowitsch   PetscCall(PetscMalloc2(n_hi,&hierarchy,n_hi,&hierarchy_forest));
46480a96aa3bSJed Brown 
46490a96aa3bSJed Brown   i = 0;
46500a96aa3bSJed Brown   hiforest = PETSC_TRUE;
46510a96aa3bSJed Brown   coarseDM = dm;
46520a96aa3bSJed Brown   do {
46530a96aa3bSJed Brown     dmIn = coarseDM;
46540a96aa3bSJed Brown     coarseDM = NULL;
46550a96aa3bSJed Brown     if (hiforest) {
46569566063dSJacob Faibussowitsch       PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM));
46570a96aa3bSJed Brown     }
46580a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
46590a96aa3bSJed Brown       hiforest = PETSC_FALSE;
46609566063dSJacob Faibussowitsch       PetscCall(DMGetCoarseDM(dmIn,&coarseDM));
46610a96aa3bSJed Brown     }
46620a96aa3bSJed Brown     i++;
46630a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
46640a96aa3bSJed Brown   } while (coarseDM);
46650a96aa3bSJed Brown 
46660a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
46679566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn,&plex));
46680a96aa3bSJed Brown 
46690a96aa3bSJed Brown   /* Check this plex is compatible with the base */
46700a96aa3bSJed Brown   {
46710a96aa3bSJed Brown     IS       gnum[2];
46720a96aa3bSJed Brown     PetscInt ncells[2],gncells[2];
46730a96aa3bSJed Brown 
46749566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(base,&gnum[0]));
46759566063dSJacob Faibussowitsch     PetscCall(DMPlexGetCellNumbering(plex,&gnum[1]));
46769566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[0],NULL,&ncells[0]));
46779566063dSJacob Faibussowitsch     PetscCall(ISGetMinMax(gnum[1],NULL,&ncells[1]));
46781c2dc1cbSBarry Smith     PetscCall(MPIU_Allreduce(ncells,gncells,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
467963a3b9bcSJacob 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);
46800a96aa3bSJed Brown   }
46810a96aa3bSJed Brown 
46829566063dSJacob Faibussowitsch   PetscCall(DMGetLabel(dmIn,"_forest_base_subpoint_map",&subpointMap));
468328b400f6SJacob Faibussowitsch   PetscCheck(subpointMap,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing _forest_base_subpoint_map label");
46840a96aa3bSJed Brown 
46859566063dSJacob Faibussowitsch   PetscCall(DMPlexGetMaxProjectionHeight(base,&mh));
46869566063dSJacob Faibussowitsch   PetscCall(DMPlexSetMaxProjectionHeight(plex,mh));
46870a96aa3bSJed Brown 
46889566063dSJacob Faibussowitsch   PetscCall(DMClone(base,&basec));
46899566063dSJacob Faibussowitsch   PetscCall(DMCopyDisc(dmVecIn,basec));
46900a96aa3bSJed Brown   if (sfRed) {
46919566063dSJacob Faibussowitsch     PetscCall(PetscObjectReference((PetscObject)vecIn));
46920a96aa3bSJed Brown     vecInLocal = vecIn;
46930a96aa3bSJed Brown   } else {
46949566063dSJacob Faibussowitsch     PetscCall(DMCreateLocalVector(basec,&vecInLocal));
46959566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalBegin(basec,vecIn,INSERT_VALUES,vecInLocal));
46969566063dSJacob Faibussowitsch     PetscCall(DMGlobalToLocalEnd(basec,vecIn,INSERT_VALUES,vecInLocal));
46970a96aa3bSJed Brown   }
46980a96aa3bSJed Brown 
46999566063dSJacob Faibussowitsch   PetscCall(DMGetLocalVector(dmIn,&vecOutLocal));
47000a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
47010a96aa3bSJed Brown     PetscSF            basetocoarse;
47020a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
47030a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
47040a96aa3bSJed Brown     PetscMPIInt        rank;
47050a96aa3bSJed Brown     PetscSFNode       *remotes;
47060a96aa3bSJed Brown     PetscSection       secIn, secOut;
47070a96aa3bSJed Brown     PetscInt          *remoteOffsets;
47080a96aa3bSJed Brown     PetscSF            transferSF;
47090a96aa3bSJed Brown     const PetscScalar *inArray;
47100a96aa3bSJed Brown     PetscScalar       *outArray;
47110a96aa3bSJed Brown 
47129566063dSJacob Faibussowitsch     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
47139566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(basec, &bStart, &bEnd));
47140a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
47159566063dSJacob Faibussowitsch     PetscCall(DMPlexGetChart(plex, &iStart, &iEnd));
47160a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
47170a96aa3bSJed Brown 
47189566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nleaves, &remotes));
47190a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
47200a96aa3bSJed Brown       PetscInt index;
47210a96aa3bSJed Brown 
47220a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
47239566063dSJacob Faibussowitsch       PetscCall(DMLabelGetValue(subpointMap, leaf, &index));
47240a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
47250a96aa3bSJed Brown     }
47260a96aa3bSJed Brown 
47279566063dSJacob Faibussowitsch     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
47289566063dSJacob Faibussowitsch     PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
47299566063dSJacob Faibussowitsch     PetscCall(PetscSFSetUp(basetocoarse));
47309566063dSJacob Faibussowitsch     PetscCall(DMGetLocalSection(basec,&secIn));
47319566063dSJacob Faibussowitsch     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn),&secOut));
47329566063dSJacob Faibussowitsch     PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
47339566063dSJacob Faibussowitsch     PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
47349566063dSJacob Faibussowitsch     PetscCall(PetscFree(remoteOffsets));
47359566063dSJacob Faibussowitsch     PetscCall(VecGetArrayWrite(vecOutLocal, &outArray));
47369566063dSJacob Faibussowitsch     PetscCall(VecGetArrayRead(vecInLocal, &inArray));
47379566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
47389566063dSJacob Faibussowitsch     PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
47399566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayRead(vecInLocal, &inArray));
47409566063dSJacob Faibussowitsch     PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray));
47419566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&transferSF));
47429566063dSJacob Faibussowitsch     PetscCall(PetscSectionDestroy(&secOut));
47439566063dSJacob Faibussowitsch     PetscCall(PetscSFDestroy(&basetocoarse));
47440a96aa3bSJed Brown   }
47459566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecInLocal));
47469566063dSJacob Faibussowitsch   PetscCall(DMDestroy(&basec));
47479566063dSJacob Faibussowitsch   PetscCall(VecDestroy(&vecIn));
47480a96aa3bSJed Brown 
47490a96aa3bSJed Brown   /* output */
47500a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
47510a96aa3bSJed Brown     Vec vecOut1, vecOut2;
47520a96aa3bSJed Brown     DM  fineDM;
47530a96aa3bSJed Brown 
47549566063dSJacob Faibussowitsch     PetscCall(DMGetGlobalVector(dmIn,&vecOut1));
47559566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut1));
47569566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal));
47570a96aa3bSJed Brown     for (i = 1; i < n_hi-1; i++) {
47580a96aa3bSJed Brown       fineDM  = hierarchy[i];
47599566063dSJacob Faibussowitsch       PetscCall(DMGetGlobalVector(fineDM,&vecOut2));
47609566063dSJacob Faibussowitsch       PetscCall(DMForestTransferVec(dmIn,vecOut1,fineDM,vecOut2,PETSC_TRUE,0.0));
47619566063dSJacob Faibussowitsch       PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1));
47620a96aa3bSJed Brown       vecOut1 = vecOut2;
47630a96aa3bSJed Brown       dmIn    = fineDM;
47640a96aa3bSJed Brown     }
47659566063dSJacob Faibussowitsch     PetscCall(DMForestTransferVec(dmIn,vecOut1,dm,vecOut,PETSC_TRUE,0.0));
47669566063dSJacob Faibussowitsch     PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1));
47670a96aa3bSJed Brown   } else {
47689566063dSJacob Faibussowitsch     PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut));
47699566063dSJacob Faibussowitsch     PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal));
47700a96aa3bSJed Brown   }
47719566063dSJacob Faibussowitsch   PetscCall(PetscFree2(hierarchy,hierarchy_forest));
47720a96aa3bSJed Brown   PetscFunctionReturn(0);
47730a96aa3bSJed Brown }
47740a96aa3bSJed Brown 
47750a96aa3bSJed Brown #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
47760a96aa3bSJed Brown static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
47770a96aa3bSJed Brown {
47780a96aa3bSJed Brown   DM             adaptIn, adaptOut, plexIn, plexOut;
47790a96aa3bSJed Brown   DM_Forest      *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
47800a96aa3bSJed Brown   PetscInt       dofPerDim[] = {1, 1, 1, 1};
47810a96aa3bSJed Brown   PetscSF        inSF = NULL, outSF = NULL;
47820a96aa3bSJed Brown   PetscInt       *inCids = NULL, *outCids = NULL;
47830a96aa3bSJed Brown   DMAdaptFlag    purposeIn, purposeOut;
47840a96aa3bSJed Brown 
47850a96aa3bSJed Brown   PetscFunctionBegin;
47860a96aa3bSJed Brown   forestOut = (DM_Forest *) dmOut->data;
47870a96aa3bSJed Brown   forestIn  = (DM_Forest *) dmIn->data;
47880a96aa3bSJed Brown 
47899566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmOut,&adaptOut));
47909566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmOut,&purposeOut));
47910a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *) adaptOut->data : NULL;
47920a96aa3bSJed Brown 
47939566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityForest(dmIn,&adaptIn));
47949566063dSJacob Faibussowitsch   PetscCall(DMForestGetAdaptivityPurpose(dmIn,&purposeIn));
47950a96aa3bSJed Brown   forestAdaptIn  = adaptIn ? (DM_Forest *) adaptIn->data : NULL;
47960a96aa3bSJed Brown 
47970a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
47980a96aa3bSJed Brown     switch (purposeOut) {
47990a96aa3bSJed Brown     case DM_ADAPT_REFINE:
48009566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48019566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48020a96aa3bSJed Brown       break;
48030a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
48040a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
48059566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&outCids));
48069566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48070a96aa3bSJed Brown       break;
48080a96aa3bSJed Brown     default:
48099566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48109566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
48119566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48129566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48130a96aa3bSJed Brown     }
48140a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
48150a96aa3bSJed Brown     switch (purposeIn) {
48160a96aa3bSJed Brown     case DM_ADAPT_REFINE:
48179566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&inCids));
48189566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48190a96aa3bSJed Brown       break;
48200a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
48210a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
48229566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48239566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48240a96aa3bSJed Brown       break;
48250a96aa3bSJed Brown     default:
48269566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
48279566063dSJacob Faibussowitsch       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
48289566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(inSF));
48299566063dSJacob Faibussowitsch       PetscCall(PetscSFSetUp(outSF));
48300a96aa3bSJed Brown     }
48310a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Only support transfer from pre-adaptivity to post-adaptivity right now");
48329566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmIn,&plexIn));
48339566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dmOut,&plexOut));
48340a96aa3bSJed Brown 
48359566063dSJacob Faibussowitsch   PetscCall(DMPlexTransferVecTree(plexIn,vecIn,plexOut,vecOut,inSF,outSF,inCids,outCids,useBCs,time));
48369566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
48379566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
48389566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&inSF));
48399566063dSJacob Faibussowitsch   PetscCall(PetscSFDestroy(&outSF));
48409566063dSJacob Faibussowitsch   PetscCall(PetscFree(inCids));
48419566063dSJacob Faibussowitsch   PetscCall(PetscFree(outCids));
48420a96aa3bSJed Brown   PetscFunctionReturn(0);
48430a96aa3bSJed Brown }
48440a96aa3bSJed Brown 
48450a96aa3bSJed Brown #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
48460a96aa3bSJed Brown static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm,DM *cdm)
48470a96aa3bSJed Brown {
48480a96aa3bSJed Brown   DM             plex;
48490a96aa3bSJed Brown 
48500a96aa3bSJed Brown   PetscFunctionBegin;
48510a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
48529566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48539566063dSJacob Faibussowitsch   PetscCall(DMGetCoordinateDM(plex,cdm));
48549566063dSJacob Faibussowitsch   PetscCall(PetscObjectReference((PetscObject)*cdm));
48550a96aa3bSJed Brown   PetscFunctionReturn(0);
48560a96aa3bSJed Brown }
48570a96aa3bSJed Brown 
48580a96aa3bSJed Brown #define VecViewLocal_pforest _append_pforest(VecViewLocal)
48590a96aa3bSJed Brown static PetscErrorCode VecViewLocal_pforest(Vec vec,PetscViewer viewer)
48600a96aa3bSJed Brown {
48610a96aa3bSJed Brown   DM             dm, plex;
48620a96aa3bSJed Brown 
48630a96aa3bSJed Brown   PetscFunctionBegin;
48649566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48659566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48669566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48679566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Local(vec,viewer));
48689566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48690a96aa3bSJed Brown   PetscFunctionReturn(0);
48700a96aa3bSJed Brown }
48710a96aa3bSJed Brown 
48720a96aa3bSJed Brown #define VecView_pforest _append_pforest(VecView)
48730a96aa3bSJed Brown static PetscErrorCode VecView_pforest(Vec vec,PetscViewer viewer)
48740a96aa3bSJed Brown {
48750a96aa3bSJed Brown   DM             dm, plex;
48760a96aa3bSJed Brown 
48770a96aa3bSJed Brown   PetscFunctionBegin;
48789566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48799566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48809566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48819566063dSJacob Faibussowitsch   PetscCall(VecView_Plex(vec,viewer));
48829566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48830a96aa3bSJed Brown   PetscFunctionReturn(0);
48840a96aa3bSJed Brown }
48850a96aa3bSJed Brown 
48860a96aa3bSJed Brown #define VecView_pforest_Native _infix_pforest(VecView,_Native)
48870a96aa3bSJed Brown static PetscErrorCode VecView_pforest_Native(Vec vec,PetscViewer viewer)
48880a96aa3bSJed Brown {
48890a96aa3bSJed Brown   DM             dm, plex;
48900a96aa3bSJed Brown 
48910a96aa3bSJed Brown   PetscFunctionBegin;
48929566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
48939566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
48949566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
48959566063dSJacob Faibussowitsch   PetscCall(VecView_Plex_Native(vec,viewer));
48969566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
48970a96aa3bSJed Brown   PetscFunctionReturn(0);
48980a96aa3bSJed Brown }
48990a96aa3bSJed Brown 
49000a96aa3bSJed Brown #define VecLoad_pforest _append_pforest(VecLoad)
49010a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest(Vec vec,PetscViewer viewer)
49020a96aa3bSJed Brown {
49030a96aa3bSJed Brown   DM             dm, plex;
49040a96aa3bSJed Brown 
49050a96aa3bSJed Brown   PetscFunctionBegin;
49069566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
49079566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49089566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
49099566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex(vec,viewer));
49109566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
49110a96aa3bSJed Brown   PetscFunctionReturn(0);
49120a96aa3bSJed Brown }
49130a96aa3bSJed Brown 
49140a96aa3bSJed Brown #define VecLoad_pforest_Native _infix_pforest(VecLoad,_Native)
49150a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest_Native(Vec vec,PetscViewer viewer)
49160a96aa3bSJed Brown {
49170a96aa3bSJed Brown   DM             dm, plex;
49180a96aa3bSJed Brown 
49190a96aa3bSJed Brown   PetscFunctionBegin;
49209566063dSJacob Faibussowitsch   PetscCall(VecGetDM(vec,&dm));
49219566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49229566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,plex));
49239566063dSJacob Faibussowitsch   PetscCall(VecLoad_Plex_Native(vec,viewer));
49249566063dSJacob Faibussowitsch   PetscCall(VecSetDM(vec,dm));
49250a96aa3bSJed Brown   PetscFunctionReturn(0);
49260a96aa3bSJed Brown }
49270a96aa3bSJed Brown 
49280a96aa3bSJed Brown #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
49290a96aa3bSJed Brown static PetscErrorCode DMCreateGlobalVector_pforest(DM dm,Vec *vec)
49300a96aa3bSJed Brown {
49310a96aa3bSJed Brown   PetscFunctionBegin;
49329566063dSJacob Faibussowitsch   PetscCall(DMCreateGlobalVector_Section_Private(dm,vec));
49339566063dSJacob Faibussowitsch   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
49349566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
49359566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
49369566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
49379566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
49380a96aa3bSJed Brown   PetscFunctionReturn(0);
49390a96aa3bSJed Brown }
49400a96aa3bSJed Brown 
49410a96aa3bSJed Brown #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
49420a96aa3bSJed Brown static PetscErrorCode DMCreateLocalVector_pforest(DM dm,Vec *vec)
49430a96aa3bSJed Brown {
49440a96aa3bSJed Brown   PetscFunctionBegin;
49459566063dSJacob Faibussowitsch   PetscCall(DMCreateLocalVector_Section_Private(dm,vec));
49469566063dSJacob Faibussowitsch   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
49470a96aa3bSJed Brown   PetscFunctionReturn(0);
49480a96aa3bSJed Brown }
49490a96aa3bSJed Brown 
49500a96aa3bSJed Brown #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
49510a96aa3bSJed Brown static PetscErrorCode DMCreateMatrix_pforest(DM dm,Mat *mat)
49520a96aa3bSJed Brown {
49530a96aa3bSJed Brown   DM             plex;
49540a96aa3bSJed Brown 
49550a96aa3bSJed Brown   PetscFunctionBegin;
49560a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49579566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49580a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only;  /* maybe this should go into forest->plex */
49599566063dSJacob Faibussowitsch   PetscCall(DMCreateMatrix(plex,mat));
49609566063dSJacob Faibussowitsch   PetscCall(MatSetDM(*mat,dm));
49610a96aa3bSJed Brown   PetscFunctionReturn(0);
49620a96aa3bSJed Brown }
49630a96aa3bSJed Brown 
49640a96aa3bSJed Brown #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
49650a96aa3bSJed Brown static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, InsertMode mode, Vec localX)
49660a96aa3bSJed Brown {
49670a96aa3bSJed Brown   DM             plex;
49680a96aa3bSJed Brown 
49690a96aa3bSJed Brown   PetscFunctionBegin;
49700a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49719566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49729566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLocal(plex,time,funcs,ctxs,mode,localX));
49730a96aa3bSJed Brown   PetscFunctionReturn(0);
49740a96aa3bSJed Brown }
49750a96aa3bSJed Brown 
49760a96aa3bSJed Brown #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
49770a96aa3bSJed 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)
49780a96aa3bSJed Brown {
49790a96aa3bSJed Brown   DM             plex;
49800a96aa3bSJed Brown 
49810a96aa3bSJed Brown   PetscFunctionBegin;
49820a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49839566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49849566063dSJacob Faibussowitsch   PetscCall(DMProjectFunctionLabelLocal(plex,time,label,numIds,ids,Ncc,comps,funcs,ctxs,mode,localX));
49850a96aa3bSJed Brown   PetscFunctionReturn(0);
49860a96aa3bSJed Brown }
49870a96aa3bSJed Brown 
49880a96aa3bSJed Brown #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
49890a96aa3bSJed Brown PetscErrorCode DMProjectFieldLocal_pforest(DM dm, PetscReal time, Vec localU,void (**funcs) (PetscInt, PetscInt, PetscInt,
49900a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
49910a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
49920a96aa3bSJed Brown                                                                              PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),InsertMode mode, Vec localX)
49930a96aa3bSJed Brown {
49940a96aa3bSJed Brown   DM             plex;
49950a96aa3bSJed Brown 
49960a96aa3bSJed Brown   PetscFunctionBegin;
49970a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
49989566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
49999566063dSJacob Faibussowitsch   PetscCall(DMProjectFieldLocal(plex,time,localU,funcs,mode,localX));
50000a96aa3bSJed Brown   PetscFunctionReturn(0);
50010a96aa3bSJed Brown }
50020a96aa3bSJed Brown 
50030a96aa3bSJed Brown #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
50040a96aa3bSJed Brown PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal *diff)
50050a96aa3bSJed Brown {
50060a96aa3bSJed Brown   DM             plex;
50070a96aa3bSJed Brown 
50080a96aa3bSJed Brown   PetscFunctionBegin;
50090a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50109566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50119566063dSJacob Faibussowitsch   PetscCall(DMComputeL2Diff(plex,time,funcs,ctxs,X,diff));
50120a96aa3bSJed Brown   PetscFunctionReturn(0);
50130a96aa3bSJed Brown }
50140a96aa3bSJed Brown 
50150a96aa3bSJed Brown #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
50160a96aa3bSJed Brown PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal diff[])
50170a96aa3bSJed Brown {
50180a96aa3bSJed Brown   DM             plex;
50190a96aa3bSJed Brown 
50200a96aa3bSJed Brown   PetscFunctionBegin;
50210a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50229566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50239566063dSJacob Faibussowitsch   PetscCall(DMComputeL2FieldDiff(plex,time,funcs,ctxs,X,diff));
50240a96aa3bSJed Brown   PetscFunctionReturn(0);
50250a96aa3bSJed Brown }
50260a96aa3bSJed Brown 
50270a96aa3bSJed Brown #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
50280a96aa3bSJed Brown static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
50290a96aa3bSJed Brown {
50300a96aa3bSJed Brown   DM             plex;
50310a96aa3bSJed Brown   PetscSection   section;
50320a96aa3bSJed Brown 
50330a96aa3bSJed Brown   PetscFunctionBegin;
50340a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50359566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50369566063dSJacob Faibussowitsch   PetscCall(DMGetLocalSection(plex,&section));
50379566063dSJacob Faibussowitsch   PetscCall(DMSetLocalSection(dm,section));
50380a96aa3bSJed Brown   PetscFunctionReturn(0);
50390a96aa3bSJed Brown }
50400a96aa3bSJed Brown 
50410a96aa3bSJed Brown #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
50420a96aa3bSJed Brown static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
50430a96aa3bSJed Brown {
50440a96aa3bSJed Brown   DM             plex;
50450a96aa3bSJed Brown   Mat            mat;
504679769bd5SJed Brown   Vec            bias;
50470a96aa3bSJed Brown   PetscSection   section;
50480a96aa3bSJed Brown 
50490a96aa3bSJed Brown   PetscFunctionBegin;
50500a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50519566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50529566063dSJacob Faibussowitsch   PetscCall(DMGetDefaultConstraints(plex,&section,&mat,&bias));
50539566063dSJacob Faibussowitsch   PetscCall(DMSetDefaultConstraints(dm,section,mat,bias));
50540a96aa3bSJed Brown   PetscFunctionReturn(0);
50550a96aa3bSJed Brown }
50560a96aa3bSJed Brown 
50570a96aa3bSJed Brown #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
50580a96aa3bSJed Brown static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
50590a96aa3bSJed Brown {
50600a96aa3bSJed Brown   DM             plex;
50610a96aa3bSJed Brown 
50620a96aa3bSJed Brown   PetscFunctionBegin;
50630a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
50649566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
50659566063dSJacob Faibussowitsch   PetscCall(DMGetDimPoints(plex,dim,cStart,cEnd));
50660a96aa3bSJed Brown   PetscFunctionReturn(0);
50670a96aa3bSJed Brown }
50680a96aa3bSJed Brown 
50690a96aa3bSJed Brown /* Need to forward declare */
50700a96aa3bSJed Brown #define DMInitialize_pforest _append_pforest(DMInitialize)
50710a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
50720a96aa3bSJed Brown 
50730a96aa3bSJed Brown #define DMClone_pforest _append_pforest(DMClone)
50740a96aa3bSJed Brown static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
50750a96aa3bSJed Brown {
50760a96aa3bSJed Brown   PetscFunctionBegin;
50779566063dSJacob Faibussowitsch   PetscCall(DMClone_Forest(dm,newdm));
50789566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(*newdm));
50790a96aa3bSJed Brown   PetscFunctionReturn(0);
50800a96aa3bSJed Brown }
50810a96aa3bSJed Brown 
50820a96aa3bSJed Brown #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
50830a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
50840a96aa3bSJed Brown {
50850a96aa3bSJed Brown   DM_Forest         *forest;
50860a96aa3bSJed Brown   DM_Forest_pforest *pforest;
50870a96aa3bSJed Brown   PetscInt          overlap;
50880a96aa3bSJed Brown 
50890a96aa3bSJed Brown   PetscFunctionBegin;
50909566063dSJacob Faibussowitsch   PetscCall(DMSetUp(dm));
50910a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
50920a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
50930a96aa3bSJed Brown   *cStart = 0;
50949566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
50950a96aa3bSJed Brown   if (overlap && pforest->ghost) {
50960a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
50970a96aa3bSJed Brown   } else {
50980a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
50990a96aa3bSJed Brown   }
51000a96aa3bSJed Brown   PetscFunctionReturn(0);
51010a96aa3bSJed Brown }
51020a96aa3bSJed Brown 
51030a96aa3bSJed Brown #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
51040a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
51050a96aa3bSJed Brown {
51060a96aa3bSJed Brown   DM_Forest         *forest;
51070a96aa3bSJed Brown   DM_Forest_pforest *pforest;
51080a96aa3bSJed Brown   PetscMPIInt       rank;
51090a96aa3bSJed Brown   PetscInt          overlap;
51100a96aa3bSJed Brown   PetscInt          cStart, cEnd, cLocalStart, cLocalEnd;
51110a96aa3bSJed Brown   PetscInt          nRoots, nLeaves, *mine = NULL;
51120a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
51130a96aa3bSJed Brown   PetscSF           sf;
51140a96aa3bSJed Brown 
51150a96aa3bSJed Brown   PetscFunctionBegin;
51169566063dSJacob Faibussowitsch   PetscCall(DMForestGetCellChart(dm,&cStart,&cEnd));
51170a96aa3bSJed Brown   forest      = (DM_Forest*)         dm->data;
51180a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
51190a96aa3bSJed Brown   nRoots      = cEnd - cStart;
51200a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
51210a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
51220a96aa3bSJed Brown   nLeaves     = 0;
51239566063dSJacob Faibussowitsch   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
51249566063dSJacob Faibussowitsch   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
51250a96aa3bSJed Brown   if (overlap && pforest->ghost) {
51260a96aa3bSJed Brown     PetscSFNode      *mirror;
51270a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
51280a96aa3bSJed Brown     PetscInt         nMirror, nGhostPre, nSelf, q;
51290a96aa3bSJed Brown     void             **mirrorPtrs;
51300a96aa3bSJed Brown 
51310a96aa3bSJed Brown     nMirror      = (PetscInt) pforest->ghost->mirrors.elem_count;
51320a96aa3bSJed Brown     nSelf        = cLocalEnd - cLocalStart;
51330a96aa3bSJed Brown     nLeaves      = nRoots - nSelf;
51340a96aa3bSJed Brown     nGhostPre    = (PetscInt) pforest->ghost->proc_offsets[rank];
51359566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves,&mine));
51369566063dSJacob Faibussowitsch     PetscCall(PetscMalloc1(nLeaves,&remote));
51379566063dSJacob Faibussowitsch     PetscCall(PetscMalloc2(nMirror,&mirror,nMirror,&mirrorPtrs));
51380a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t*) pforest->ghost->mirrors.array;
51390a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
51400a96aa3bSJed Brown       p4est_quadrant_t *mir = &(mirror_array[q]);
51410a96aa3bSJed Brown 
51420a96aa3bSJed Brown       mirror[q].rank  = rank;
51430a96aa3bSJed Brown       mirror[q].index = (PetscInt) mir->p.piggy3.local_num + cLocalStart;
51440a96aa3bSJed Brown       mirrorPtrs[q]   = (void*) &(mirror[q]);
51450a96aa3bSJed Brown     }
51460a96aa3bSJed Brown     PetscStackCallP4est(p4est_ghost_exchange_custom,(pforest->forest,pforest->ghost,sizeof(PetscSFNode),mirrorPtrs,remote));
51479566063dSJacob Faibussowitsch     PetscCall(PetscFree2(mirror,mirrorPtrs));
51480a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
51490a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
51500a96aa3bSJed Brown   }
51519566063dSJacob Faibussowitsch   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&sf));
51529566063dSJacob Faibussowitsch   PetscCall(PetscSFSetGraph(sf,nRoots,nLeaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
51530a96aa3bSJed Brown   *cellSF = sf;
51540a96aa3bSJed Brown   PetscFunctionReturn(0);
51550a96aa3bSJed Brown }
51560a96aa3bSJed Brown 
51570a96aa3bSJed Brown static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS* ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void*), void **setup_ctx)
51580a96aa3bSJed Brown {
51590a96aa3bSJed Brown   DM             plex;
51600a96aa3bSJed Brown 
51610a96aa3bSJed Brown   PetscFunctionBegin;
51629566063dSJacob Faibussowitsch   PetscCall(DMPforestGetPlex(dm,&plex));
51639566063dSJacob Faibussowitsch   PetscCall(DMCreateNeumannOverlap_Plex(plex,ovl,J,setup,setup_ctx));
51640a96aa3bSJed Brown   if (!*setup) {
51659566063dSJacob Faibussowitsch     PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
51660a96aa3bSJed Brown     if (*setup) {
51679566063dSJacob Faibussowitsch       PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
51680a96aa3bSJed Brown     }
51690a96aa3bSJed Brown   }
51700a96aa3bSJed Brown   PetscFunctionReturn(0);
51710a96aa3bSJed Brown }
51720a96aa3bSJed Brown 
51730a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm)
51740a96aa3bSJed Brown {
51750a96aa3bSJed Brown   PetscFunctionBegin;
51760a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
51770a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
51780a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
51790a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
51800a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
51810a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
51820a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
51830a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
51840a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
51850a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
51860a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
51870a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
51880a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
51890a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
51900a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
51910a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
51920a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
51930a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
51940a96aa3bSJed Brown 
51959566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",DMConvert_plex_pforest));
51969566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",DMConvert_pforest_plex));
51979566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_pforest));
51989566063dSJacob Faibussowitsch   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMForestGetPartitionOverlap));
51990a96aa3bSJed Brown   PetscFunctionReturn(0);
52000a96aa3bSJed Brown }
52010a96aa3bSJed Brown 
52020a96aa3bSJed Brown #define DMCreate_pforest _append_pforest(DMCreate)
52030a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
52040a96aa3bSJed Brown {
52050a96aa3bSJed Brown   DM_Forest         *forest;
52060a96aa3bSJed Brown   DM_Forest_pforest *pforest;
52070a96aa3bSJed Brown 
52080a96aa3bSJed Brown   PetscFunctionBegin;
52099566063dSJacob Faibussowitsch   PetscCall(PetscP4estInitialize());
52109566063dSJacob Faibussowitsch   PetscCall(DMCreate_Forest(dm));
52119566063dSJacob Faibussowitsch   PetscCall(DMInitialize_pforest(dm));
52129566063dSJacob Faibussowitsch   PetscCall(DMSetDimension(dm,P4EST_DIM));
52130a96aa3bSJed Brown 
52140a96aa3bSJed Brown   /* set forest defaults */
52159566063dSJacob Faibussowitsch   PetscCall(DMForestSetTopology(dm,"unit"));
52169566063dSJacob Faibussowitsch   PetscCall(DMForestSetMinimumRefinement(dm,0));
52179566063dSJacob Faibussowitsch   PetscCall(DMForestSetInitialRefinement(dm,0));
52189566063dSJacob Faibussowitsch   PetscCall(DMForestSetMaximumRefinement(dm,P4EST_QMAXLEVEL));
52199566063dSJacob Faibussowitsch   PetscCall(DMForestSetGradeFactor(dm,2));
52209566063dSJacob Faibussowitsch   PetscCall(DMForestSetAdjacencyDimension(dm,0));
52219566063dSJacob Faibussowitsch   PetscCall(DMForestSetPartitionOverlap(dm,0));
52220a96aa3bSJed Brown 
52230a96aa3bSJed Brown   /* create p4est data */
52249566063dSJacob Faibussowitsch   PetscCall(PetscNewLog(dm,&pforest));
52250a96aa3bSJed Brown 
52260a96aa3bSJed Brown   forest                            = (DM_Forest*) dm->data;
52270a96aa3bSJed Brown   forest->data                      = pforest;
52280a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
52290a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
52300a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
52310a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
52320a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
52330a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
52340a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
52350a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
52360a96aa3bSJed Brown   pforest->topo                     = NULL;
52370a96aa3bSJed Brown   pforest->forest                   = NULL;
52380a96aa3bSJed Brown   pforest->ghost                    = NULL;
52390a96aa3bSJed Brown   pforest->lnodes                   = NULL;
52400a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
52410a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
52420a96aa3bSJed Brown   pforest->cLocalStart              = -1;
52430a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
52440a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
52450a96aa3bSJed Brown   pforest->ghostName                = NULL;
52460a96aa3bSJed Brown   PetscFunctionReturn(0);
52470a96aa3bSJed Brown }
52480a96aa3bSJed Brown 
52490a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5250