xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 0a96aa3bf9dab2395989eff53b4fb976d4f05537)
1*0a96aa3bSJed Brown #include <petscds.h>
2*0a96aa3bSJed Brown #include <petsc/private/dmimpl.h>
3*0a96aa3bSJed Brown #include <petsc/private/dmforestimpl.h>
4*0a96aa3bSJed Brown #include <petsc/private/dmpleximpl.h>
5*0a96aa3bSJed Brown #include <petsc/private/dmlabelimpl.h>
6*0a96aa3bSJed Brown #include <petsc/private/viewerimpl.h>
7*0a96aa3bSJed Brown #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h>
8*0a96aa3bSJed Brown #include "petsc_p4est_package.h"
9*0a96aa3bSJed Brown 
10*0a96aa3bSJed Brown #if defined(PETSC_HAVE_P4EST)
11*0a96aa3bSJed Brown 
12*0a96aa3bSJed Brown #if !defined(P4_TO_P8)
13*0a96aa3bSJed Brown #include <p4est.h>
14*0a96aa3bSJed Brown #include <p4est_extended.h>
15*0a96aa3bSJed Brown #include <p4est_geometry.h>
16*0a96aa3bSJed Brown #include <p4est_ghost.h>
17*0a96aa3bSJed Brown #include <p4est_lnodes.h>
18*0a96aa3bSJed Brown #include <p4est_vtk.h>
19*0a96aa3bSJed Brown #include <p4est_plex.h>
20*0a96aa3bSJed Brown #include <p4est_bits.h>
21*0a96aa3bSJed Brown #include <p4est_algorithms.h>
22*0a96aa3bSJed Brown #else
23*0a96aa3bSJed Brown #include <p8est.h>
24*0a96aa3bSJed Brown #include <p8est_extended.h>
25*0a96aa3bSJed Brown #include <p8est_geometry.h>
26*0a96aa3bSJed Brown #include <p8est_ghost.h>
27*0a96aa3bSJed Brown #include <p8est_lnodes.h>
28*0a96aa3bSJed Brown #include <p8est_vtk.h>
29*0a96aa3bSJed Brown #include <p8est_plex.h>
30*0a96aa3bSJed Brown #include <p8est_bits.h>
31*0a96aa3bSJed Brown #include <p8est_algorithms.h>
32*0a96aa3bSJed Brown #endif
33*0a96aa3bSJed Brown 
34*0a96aa3bSJed Brown typedef enum {PATTERN_HASH,PATTERN_FRACTAL,PATTERN_CORNER,PATTERN_CENTER,PATTERN_COUNT} DMRefinePattern;
35*0a96aa3bSJed Brown static const char *DMRefinePatternName[PATTERN_COUNT] = {"hash","fractal","corner","center"};
36*0a96aa3bSJed Brown 
37*0a96aa3bSJed Brown typedef struct _DMRefinePatternCtx
38*0a96aa3bSJed Brown {
39*0a96aa3bSJed Brown   PetscInt       corner;
40*0a96aa3bSJed Brown   PetscBool      fractal[P4EST_CHILDREN];
41*0a96aa3bSJed Brown   PetscReal      hashLikelihood;
42*0a96aa3bSJed Brown   PetscInt       maxLevel;
43*0a96aa3bSJed Brown   p4est_refine_t refine_fn;
44*0a96aa3bSJed Brown }
45*0a96aa3bSJed Brown DMRefinePatternCtx;
46*0a96aa3bSJed Brown 
47*0a96aa3bSJed Brown static int DMRefinePattern_Corner(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
48*0a96aa3bSJed Brown {
49*0a96aa3bSJed Brown   p4est_quadrant_t   root, rootcorner;
50*0a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
51*0a96aa3bSJed Brown 
52*0a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
53*0a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
54*0a96aa3bSJed Brown 
55*0a96aa3bSJed Brown   root.x = root.y = 0;
56*0a96aa3bSJed Brown #if defined(P4_TO_P8)
57*0a96aa3bSJed Brown   root.z = 0;
58*0a96aa3bSJed Brown #endif
59*0a96aa3bSJed Brown   root.level = 0;
60*0a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&root,&rootcorner,ctx->corner,quadrant->level);
61*0a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant,&rootcorner)) return 1;
62*0a96aa3bSJed Brown   return 0;
63*0a96aa3bSJed Brown }
64*0a96aa3bSJed Brown 
65*0a96aa3bSJed Brown static int DMRefinePattern_Center(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
66*0a96aa3bSJed Brown {
67*0a96aa3bSJed Brown   int                cid;
68*0a96aa3bSJed Brown   p4est_quadrant_t   ancestor, ancestorcorner;
69*0a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
70*0a96aa3bSJed Brown 
71*0a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
72*0a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
73*0a96aa3bSJed Brown   if (quadrant->level <= 1) return 1;
74*0a96aa3bSJed Brown 
75*0a96aa3bSJed Brown   p4est_quadrant_ancestor(quadrant,1,&ancestor);
76*0a96aa3bSJed Brown   cid = p4est_quadrant_child_id(&ancestor);
77*0a96aa3bSJed Brown   p4est_quadrant_corner_descendant(&ancestor,&ancestorcorner,P4EST_CHILDREN - 1 - cid,quadrant->level);
78*0a96aa3bSJed Brown   if (p4est_quadrant_is_equal(quadrant,&ancestorcorner)) return 1;
79*0a96aa3bSJed Brown   return 0;
80*0a96aa3bSJed Brown }
81*0a96aa3bSJed Brown 
82*0a96aa3bSJed Brown static int DMRefinePattern_Fractal(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
83*0a96aa3bSJed Brown {
84*0a96aa3bSJed Brown   int                cid;
85*0a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
86*0a96aa3bSJed Brown 
87*0a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
88*0a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
89*0a96aa3bSJed Brown   if (!quadrant->level) return 1;
90*0a96aa3bSJed Brown   cid = p4est_quadrant_child_id(quadrant);
91*0a96aa3bSJed Brown   if (ctx->fractal[cid ^ ((int) (quadrant->level % P4EST_CHILDREN))]) return 1;
92*0a96aa3bSJed Brown   return 0;
93*0a96aa3bSJed Brown }
94*0a96aa3bSJed Brown 
95*0a96aa3bSJed Brown /* simplified from MurmurHash3 by Austin Appleby */
96*0a96aa3bSJed Brown #define DMPROT32(x, y) ((x << y) | (x >> (32 - y)))
97*0a96aa3bSJed Brown static uint32_t DMPforestHash(const uint32_t *blocks, uint32_t nblocks)
98*0a96aa3bSJed Brown {
99*0a96aa3bSJed Brown   uint32_t c1   = 0xcc9e2d51;
100*0a96aa3bSJed Brown   uint32_t c2   = 0x1b873593;
101*0a96aa3bSJed Brown   uint32_t r1   = 15;
102*0a96aa3bSJed Brown   uint32_t r2   = 13;
103*0a96aa3bSJed Brown   uint32_t m    = 5;
104*0a96aa3bSJed Brown   uint32_t n    = 0xe6546b64;
105*0a96aa3bSJed Brown   uint32_t hash = 0;
106*0a96aa3bSJed Brown   int      len  = nblocks * 4;
107*0a96aa3bSJed Brown   uint32_t i;
108*0a96aa3bSJed Brown 
109*0a96aa3bSJed Brown   for (i = 0; i < nblocks; i++) {
110*0a96aa3bSJed Brown     uint32_t k;
111*0a96aa3bSJed Brown 
112*0a96aa3bSJed Brown     k  = blocks[i];
113*0a96aa3bSJed Brown     k *= c1;
114*0a96aa3bSJed Brown     k  = DMPROT32(k, r1);
115*0a96aa3bSJed Brown     k *= c2;
116*0a96aa3bSJed Brown 
117*0a96aa3bSJed Brown     hash ^= k;
118*0a96aa3bSJed Brown     hash  = DMPROT32(hash, r2) * m + n;
119*0a96aa3bSJed Brown   }
120*0a96aa3bSJed Brown 
121*0a96aa3bSJed Brown   hash ^= len;
122*0a96aa3bSJed Brown   hash ^= (hash >> 16);
123*0a96aa3bSJed Brown   hash *= 0x85ebca6b;
124*0a96aa3bSJed Brown   hash ^= (hash >> 13);
125*0a96aa3bSJed Brown   hash *= 0xc2b2ae35;
126*0a96aa3bSJed Brown   hash ^= (hash >> 16);
127*0a96aa3bSJed Brown 
128*0a96aa3bSJed Brown   return hash;
129*0a96aa3bSJed Brown }
130*0a96aa3bSJed Brown 
131*0a96aa3bSJed Brown #if defined(UINT32_MAX)
132*0a96aa3bSJed Brown #define DMP4EST_HASH_MAX UINT32_MAX
133*0a96aa3bSJed Brown #else
134*0a96aa3bSJed Brown #define DMP4EST_HASH_MAX ((uint32_t) 0xffffffff)
135*0a96aa3bSJed Brown #endif
136*0a96aa3bSJed Brown 
137*0a96aa3bSJed Brown static int DMRefinePattern_Hash(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
138*0a96aa3bSJed Brown {
139*0a96aa3bSJed Brown   uint32_t           data[5];
140*0a96aa3bSJed Brown   uint32_t           result;
141*0a96aa3bSJed Brown   DMRefinePatternCtx *ctx;
142*0a96aa3bSJed Brown 
143*0a96aa3bSJed Brown   ctx = (DMRefinePatternCtx*) p4est->user_pointer;
144*0a96aa3bSJed Brown   if (quadrant->level >= ctx->maxLevel) return 0;
145*0a96aa3bSJed Brown   data[0] = ((uint32_t) quadrant->level) << 24;
146*0a96aa3bSJed Brown   data[1] = (uint32_t) which_tree;
147*0a96aa3bSJed Brown   data[2] = (uint32_t) quadrant->x;
148*0a96aa3bSJed Brown   data[3] = (uint32_t) quadrant->y;
149*0a96aa3bSJed Brown #if defined(P4_TO_P8)
150*0a96aa3bSJed Brown   data[4] = (uint32_t) quadrant->z;
151*0a96aa3bSJed Brown #endif
152*0a96aa3bSJed Brown 
153*0a96aa3bSJed Brown   result = DMPforestHash(data,2+P4EST_DIM);
154*0a96aa3bSJed Brown   if (((double) result / (double) DMP4EST_HASH_MAX) < ctx->hashLikelihood) return 1;
155*0a96aa3bSJed Brown   return 0;
156*0a96aa3bSJed Brown }
157*0a96aa3bSJed Brown 
158*0a96aa3bSJed Brown #define DMConvert_pforest_plex _infix_pforest(DMConvert,_plex)
159*0a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM,DMType,DM*);
160*0a96aa3bSJed Brown 
161*0a96aa3bSJed Brown #define DMFTopology_pforest _append_pforest(DMFTopology)
162*0a96aa3bSJed Brown typedef struct {
163*0a96aa3bSJed Brown   PetscInt             refct;
164*0a96aa3bSJed Brown   p4est_connectivity_t *conn;
165*0a96aa3bSJed Brown   p4est_geometry_t     *geom;
166*0a96aa3bSJed Brown   PetscInt             *tree_face_to_uniq; /* p4est does not explicitly enumerate facets, but we must to keep track of labels */
167*0a96aa3bSJed Brown } DMFTopology_pforest;
168*0a96aa3bSJed Brown 
169*0a96aa3bSJed Brown #define DM_Forest_pforest _append_pforest(DM_Forest)
170*0a96aa3bSJed Brown typedef struct {
171*0a96aa3bSJed Brown   DMFTopology_pforest *topo;
172*0a96aa3bSJed Brown   p4est_t             *forest;
173*0a96aa3bSJed Brown   p4est_ghost_t       *ghost;
174*0a96aa3bSJed Brown   p4est_lnodes_t      *lnodes;
175*0a96aa3bSJed Brown   PetscBool           partition_for_coarsening;
176*0a96aa3bSJed Brown   PetscBool           coarsen_hierarchy;
177*0a96aa3bSJed Brown   PetscBool           labelsFinalized;
178*0a96aa3bSJed Brown   PetscBool           adaptivitySuccess;
179*0a96aa3bSJed Brown   PetscInt            cLocalStart;
180*0a96aa3bSJed Brown   PetscInt            cLocalEnd;
181*0a96aa3bSJed Brown   DM                  plex;
182*0a96aa3bSJed Brown   char                *ghostName;
183*0a96aa3bSJed Brown   PetscSF             pointAdaptToSelfSF;
184*0a96aa3bSJed Brown   PetscSF             pointSelfToAdaptSF;
185*0a96aa3bSJed Brown   PetscInt            *pointAdaptToSelfCids;
186*0a96aa3bSJed Brown   PetscInt            *pointSelfToAdaptCids;
187*0a96aa3bSJed Brown } DM_Forest_pforest;
188*0a96aa3bSJed Brown 
189*0a96aa3bSJed Brown #define DM_Forest_geometry_pforest _append_pforest(DM_Forest_geometry)
190*0a96aa3bSJed Brown typedef struct {
191*0a96aa3bSJed Brown   DM base;
192*0a96aa3bSJed Brown   PetscErrorCode   (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void*);
193*0a96aa3bSJed Brown   void             *mapCtx;
194*0a96aa3bSJed Brown   PetscInt         coordDim;
195*0a96aa3bSJed Brown   p4est_geometry_t *inner;
196*0a96aa3bSJed Brown }
197*0a96aa3bSJed Brown DM_Forest_geometry_pforest;
198*0a96aa3bSJed Brown 
199*0a96aa3bSJed Brown #define GeometryMapping_pforest _append_pforest(GeometryMapping)
200*0a96aa3bSJed Brown static void GeometryMapping_pforest(p4est_geometry_t *geom, p4est_topidx_t which_tree, const double abc[3], double xyz[3])
201*0a96aa3bSJed Brown {
202*0a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user;
203*0a96aa3bSJed Brown   PetscReal                  PetscABC[3]   = {0.};
204*0a96aa3bSJed Brown   PetscReal                  PetscXYZ[3]   = {0.};
205*0a96aa3bSJed Brown   PetscInt                   i, d = PetscMin(3,geom_pforest->coordDim);
206*0a96aa3bSJed Brown   double                     ABC[3];
207*0a96aa3bSJed Brown   PetscErrorCode             ierr;
208*0a96aa3bSJed Brown 
209*0a96aa3bSJed Brown   (geom_pforest->inner->X)(geom_pforest->inner,which_tree,abc,ABC);
210*0a96aa3bSJed Brown 
211*0a96aa3bSJed Brown   for (i = 0; i < d; i++) PetscABC[i] = ABC[i];
212*0a96aa3bSJed Brown   ierr = (geom_pforest->map)(geom_pforest->base,(PetscInt) which_tree,geom_pforest->coordDim,PetscABC,PetscXYZ,geom_pforest->mapCtx);PETSC_P4EST_ASSERT(!ierr);
213*0a96aa3bSJed Brown   for (i = 0; i < d; i++) xyz[i] = PetscXYZ[i];
214*0a96aa3bSJed Brown }
215*0a96aa3bSJed Brown 
216*0a96aa3bSJed Brown #define GeometryDestroy_pforest _append_pforest(GeometryDestroy)
217*0a96aa3bSJed Brown static void GeometryDestroy_pforest(p4est_geometry_t *geom)
218*0a96aa3bSJed Brown {
219*0a96aa3bSJed Brown   DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user;
220*0a96aa3bSJed Brown   PetscErrorCode             ierr;
221*0a96aa3bSJed Brown 
222*0a96aa3bSJed Brown   p4est_geometry_destroy(geom_pforest->inner);
223*0a96aa3bSJed Brown   ierr = PetscFree(geom->user);PETSC_P4EST_ASSERT(!ierr);
224*0a96aa3bSJed Brown   ierr = PetscFree(geom);PETSC_P4EST_ASSERT(!ierr);
225*0a96aa3bSJed Brown }
226*0a96aa3bSJed Brown 
227*0a96aa3bSJed Brown #define DMFTopologyDestroy_pforest _append_pforest(DMFTopologyDestroy)
228*0a96aa3bSJed Brown static PetscErrorCode DMFTopologyDestroy_pforest(DMFTopology_pforest **topo)
229*0a96aa3bSJed Brown {
230*0a96aa3bSJed Brown   PetscErrorCode ierr;
231*0a96aa3bSJed Brown 
232*0a96aa3bSJed Brown   PetscFunctionBegin;
233*0a96aa3bSJed Brown   if (!(*topo)) PetscFunctionReturn(0);
234*0a96aa3bSJed Brown   if (--((*topo)->refct) > 0) {
235*0a96aa3bSJed Brown     *topo = NULL;
236*0a96aa3bSJed Brown     PetscFunctionReturn(0);
237*0a96aa3bSJed Brown   }
238*0a96aa3bSJed Brown   if ((*topo)->geom) PetscStackCallP4est(p4est_geometry_destroy,((*topo)->geom));
239*0a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,((*topo)->conn));
240*0a96aa3bSJed Brown   ierr  = PetscFree((*topo)->tree_face_to_uniq);CHKERRQ(ierr);
241*0a96aa3bSJed Brown   ierr  = PetscFree(*topo);CHKERRQ(ierr);
242*0a96aa3bSJed Brown   *topo = NULL;
243*0a96aa3bSJed Brown   PetscFunctionReturn(0);
244*0a96aa3bSJed Brown }
245*0a96aa3bSJed Brown 
246*0a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t*,PetscInt**);
247*0a96aa3bSJed Brown 
248*0a96aa3bSJed Brown #define DMFTopologyCreateBrick_pforest _append_pforest(DMFTopologyCreateBrick)
249*0a96aa3bSJed Brown static PetscErrorCode DMFTopologyCreateBrick_pforest(DM dm,PetscInt N[], PetscInt P[], PetscReal B[],DMFTopology_pforest **topo, PetscBool useMorton)
250*0a96aa3bSJed Brown {
251*0a96aa3bSJed Brown   double         *vertices;
252*0a96aa3bSJed Brown   PetscInt       i, numVerts;
253*0a96aa3bSJed Brown   PetscErrorCode ierr;
254*0a96aa3bSJed Brown 
255*0a96aa3bSJed Brown   PetscFunctionBegin;
256*0a96aa3bSJed Brown   if (!useMorton) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Lexicographic ordering not implemented yet");
257*0a96aa3bSJed Brown   ierr = PetscNewLog(dm,topo);CHKERRQ(ierr);
258*0a96aa3bSJed Brown 
259*0a96aa3bSJed Brown   (*topo)->refct = 1;
260*0a96aa3bSJed Brown #if !defined(P4_TO_P8)
261*0a96aa3bSJed 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));
262*0a96aa3bSJed Brown #else
263*0a96aa3bSJed 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));
264*0a96aa3bSJed Brown #endif
265*0a96aa3bSJed Brown   numVerts = (*topo)->conn->num_vertices;
266*0a96aa3bSJed Brown   vertices = (*topo)->conn->vertices;
267*0a96aa3bSJed Brown   for (i = 0; i < 3 * numVerts; i++) {
268*0a96aa3bSJed Brown     PetscInt j = i % 3;
269*0a96aa3bSJed Brown 
270*0a96aa3bSJed Brown     vertices[i] = B[2 * j] + (vertices[i]/N[j]) * (B[2 * j + 1] - B[2 * j]);
271*0a96aa3bSJed Brown   }
272*0a96aa3bSJed Brown   (*topo)->geom = NULL;
273*0a96aa3bSJed Brown   ierr          = PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq);CHKERRQ(ierr);
274*0a96aa3bSJed Brown   PetscFunctionReturn(0);
275*0a96aa3bSJed Brown }
276*0a96aa3bSJed Brown 
277*0a96aa3bSJed Brown #define DMFTopologyCreate_pforest _append_pforest(DMFTopologyCreate)
278*0a96aa3bSJed Brown static PetscErrorCode DMFTopologyCreate_pforest(DM dm, DMForestTopology topologyName, DMFTopology_pforest **topo)
279*0a96aa3bSJed Brown {
280*0a96aa3bSJed Brown   const char     *name = (const char*) topologyName;
281*0a96aa3bSJed Brown   const char     *prefix;
282*0a96aa3bSJed Brown   PetscBool      isBrick, isShell, isSphere, isMoebius;
283*0a96aa3bSJed Brown   PetscErrorCode ierr;
284*0a96aa3bSJed Brown 
285*0a96aa3bSJed Brown   PetscFunctionBegin;
286*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
287*0a96aa3bSJed Brown   PetscValidCharPointer(name,2);
288*0a96aa3bSJed Brown   PetscValidPointer(topo,3);
289*0a96aa3bSJed Brown   ierr = PetscStrcmp(name,"brick",&isBrick);CHKERRQ(ierr);
290*0a96aa3bSJed Brown   ierr = PetscStrcmp(name,"shell",&isShell);CHKERRQ(ierr);
291*0a96aa3bSJed Brown   ierr = PetscStrcmp(name,"sphere",&isSphere);CHKERRQ(ierr);
292*0a96aa3bSJed Brown   ierr = PetscStrcmp(name,"moebius",&isMoebius);CHKERRQ(ierr);
293*0a96aa3bSJed Brown   ierr = PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix);CHKERRQ(ierr);
294*0a96aa3bSJed Brown   if (isBrick) {
295*0a96aa3bSJed Brown     PetscBool flgN, flgP, flgM, flgB, useMorton = PETSC_TRUE, periodic = PETSC_FALSE;
296*0a96aa3bSJed Brown     PetscInt  N[3] = {2,2,2}, P[3] = {0,0,0}, nretN = P4EST_DIM, nretP = P4EST_DIM, nretB = 2 * P4EST_DIM, i;
297*0a96aa3bSJed Brown     PetscReal B[6] = {0.0,1.0,0.0,1.0,0.0,1.0};
298*0a96aa3bSJed Brown 
299*0a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
300*0a96aa3bSJed Brown       ierr = PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_size",N,&nretN,&flgN);CHKERRQ(ierr);
301*0a96aa3bSJed Brown       ierr = PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_periodicity",P,&nretP,&flgP);CHKERRQ(ierr);
302*0a96aa3bSJed Brown       ierr = PetscOptionsGetRealArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_bounds",B,&nretB,&flgB);CHKERRQ(ierr);
303*0a96aa3bSJed Brown       ierr = PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_use_morton_curve",&useMorton,&flgM);CHKERRQ(ierr);
304*0a96aa3bSJed Brown       if (flgN && nretN != P4EST_DIM) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d sizes in -dm_p4est_brick_size, gave %d",P4EST_DIM,nretN);
305*0a96aa3bSJed Brown       if (flgP && nretP != P4EST_DIM) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d periodicities in -dm_p4est_brick_periodicity, gave %d",P4EST_DIM,nretP);
306*0a96aa3bSJed Brown       if (flgB && nretB != 2 * P4EST_DIM) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d bounds in -dm_p4est_brick_bounds, gave %d",P4EST_DIM,nretP);
307*0a96aa3bSJed Brown     }
308*0a96aa3bSJed Brown     for (i = 0; i < P4EST_DIM; i++) {
309*0a96aa3bSJed Brown       P[i]  = (P[i] ? DM_BOUNDARY_PERIODIC : DM_BOUNDARY_NONE);
310*0a96aa3bSJed Brown       periodic = (PetscBool)(P[i] || periodic);
311*0a96aa3bSJed Brown       if (!flgB) B[2 * i + 1] = N[i];
312*0a96aa3bSJed Brown     }
313*0a96aa3bSJed Brown     ierr = DMFTopologyCreateBrick_pforest(dm,N,P,B,topo,useMorton);CHKERRQ(ierr);
314*0a96aa3bSJed Brown     /* the maxCell trick is not robust enough, localize on all cells if periodic */
315*0a96aa3bSJed Brown     ierr = DMSetPeriodicity(dm,periodic,NULL,NULL,NULL);CHKERRQ(ierr);
316*0a96aa3bSJed Brown   } else {
317*0a96aa3bSJed Brown     ierr = PetscNewLog(dm,topo);CHKERRQ(ierr);
318*0a96aa3bSJed Brown 
319*0a96aa3bSJed Brown     (*topo)->refct = 1;
320*0a96aa3bSJed Brown     PetscStackCallP4estReturn((*topo)->conn,p4est_connectivity_new_byname,(name));
321*0a96aa3bSJed Brown     (*topo)->geom = NULL;
322*0a96aa3bSJed Brown     if (isMoebius) {
323*0a96aa3bSJed Brown       ierr = DMSetCoordinateDim(dm,3);CHKERRQ(ierr);
324*0a96aa3bSJed Brown     }
325*0a96aa3bSJed Brown #if defined(P4_TO_P8)
326*0a96aa3bSJed Brown     if (isShell) {
327*0a96aa3bSJed Brown       PetscReal R2 = 1., R1 = .55;
328*0a96aa3bSJed Brown 
329*0a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
330*0a96aa3bSJed Brown         ierr = PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_outer_radius",&R2,NULL);CHKERRQ(ierr);
331*0a96aa3bSJed Brown         ierr = PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_inner_radius",&R1,NULL);CHKERRQ(ierr);
332*0a96aa3bSJed Brown       }
333*0a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_shell,((*topo)->conn,R2,R1));
334*0a96aa3bSJed Brown     } else if (isSphere) {
335*0a96aa3bSJed Brown       PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856;
336*0a96aa3bSJed Brown 
337*0a96aa3bSJed Brown       if (dm->setfromoptionscalled) {
338*0a96aa3bSJed Brown         ierr = PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_outer_radius",&R2,NULL);CHKERRQ(ierr);
339*0a96aa3bSJed Brown         ierr = PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_inner_radius",&R1,NULL);CHKERRQ(ierr);
340*0a96aa3bSJed Brown         ierr = PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_core_radius",&R0,NULL);CHKERRQ(ierr);
341*0a96aa3bSJed Brown       }
342*0a96aa3bSJed Brown       PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_sphere,((*topo)->conn,R2,R1,R0));
343*0a96aa3bSJed Brown     }
344*0a96aa3bSJed Brown #endif
345*0a96aa3bSJed Brown     ierr = PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq);CHKERRQ(ierr);
346*0a96aa3bSJed Brown   }
347*0a96aa3bSJed Brown   PetscFunctionReturn(0);
348*0a96aa3bSJed Brown }
349*0a96aa3bSJed Brown 
350*0a96aa3bSJed Brown #define DMConvert_plex_pforest _append_pforest(DMConvert_plex)
351*0a96aa3bSJed Brown static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest)
352*0a96aa3bSJed Brown {
353*0a96aa3bSJed Brown   MPI_Comm       comm;
354*0a96aa3bSJed Brown   PetscBool      isPlex;
355*0a96aa3bSJed Brown   PetscInt       dim;
356*0a96aa3bSJed Brown   void           *ctx;
357*0a96aa3bSJed Brown   PetscErrorCode ierr;
358*0a96aa3bSJed Brown 
359*0a96aa3bSJed Brown   PetscFunctionBegin;
360*0a96aa3bSJed Brown 
361*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
362*0a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
363*0a96aa3bSJed Brown   ierr = PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex);CHKERRQ(ierr);
364*0a96aa3bSJed Brown   if (!isPlex) SETERRQ2(comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPLEX,((PetscObject)dm)->type_name);
365*0a96aa3bSJed Brown   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
366*0a96aa3bSJed Brown   if (dim != P4EST_DIM) SETERRQ2(comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %d",P4EST_DIM,dim);
367*0a96aa3bSJed Brown   ierr = DMCreate(comm,pforest);CHKERRQ(ierr);
368*0a96aa3bSJed Brown   ierr = DMSetType(*pforest,DMPFOREST);CHKERRQ(ierr);
369*0a96aa3bSJed Brown   ierr = DMForestSetBaseDM(*pforest,dm);CHKERRQ(ierr);
370*0a96aa3bSJed Brown   ierr = DMGetApplicationContext(dm,&ctx);CHKERRQ(ierr);
371*0a96aa3bSJed Brown   ierr = DMSetApplicationContext(*pforest,ctx);CHKERRQ(ierr);
372*0a96aa3bSJed Brown   ierr = DMCopyDisc(dm,*pforest);CHKERRQ(ierr);
373*0a96aa3bSJed Brown   PetscFunctionReturn(0);
374*0a96aa3bSJed Brown }
375*0a96aa3bSJed Brown 
376*0a96aa3bSJed Brown #define DMForestDestroy_pforest _append_pforest(DMForestDestroy)
377*0a96aa3bSJed Brown static PetscErrorCode DMForestDestroy_pforest(DM dm)
378*0a96aa3bSJed Brown {
379*0a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
380*0a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
381*0a96aa3bSJed Brown   PetscErrorCode    ierr;
382*0a96aa3bSJed Brown 
383*0a96aa3bSJed Brown   PetscFunctionBegin;
384*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
385*0a96aa3bSJed Brown   if (pforest->lnodes) PetscStackCallP4est(p4est_lnodes_destroy,(pforest->lnodes));
386*0a96aa3bSJed Brown   pforest->lnodes = NULL;
387*0a96aa3bSJed Brown   if (pforest->ghost) PetscStackCallP4est(p4est_ghost_destroy,(pforest->ghost));
388*0a96aa3bSJed Brown   pforest->ghost = NULL;
389*0a96aa3bSJed Brown   if (pforest->forest) PetscStackCallP4est(p4est_destroy,(pforest->forest));
390*0a96aa3bSJed Brown   pforest->forest = NULL;
391*0a96aa3bSJed Brown   ierr            = DMFTopologyDestroy_pforest(&pforest->topo);CHKERRQ(ierr);
392*0a96aa3bSJed Brown   ierr            = PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",NULL);CHKERRQ(ierr);
393*0a96aa3bSJed Brown   ierr            = PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",NULL);CHKERRQ(ierr);
394*0a96aa3bSJed Brown   ierr            = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",NULL);CHKERRQ(ierr);
395*0a96aa3bSJed Brown   ierr            = PetscFree(pforest->ghostName);CHKERRQ(ierr);
396*0a96aa3bSJed Brown   ierr            = DMDestroy(&pforest->plex);CHKERRQ(ierr);
397*0a96aa3bSJed Brown   ierr            = PetscSFDestroy(&pforest->pointAdaptToSelfSF);CHKERRQ(ierr);
398*0a96aa3bSJed Brown   ierr            = PetscSFDestroy(&pforest->pointSelfToAdaptSF);CHKERRQ(ierr);
399*0a96aa3bSJed Brown   ierr            = PetscFree(pforest->pointAdaptToSelfCids);CHKERRQ(ierr);
400*0a96aa3bSJed Brown   ierr            = PetscFree(pforest->pointSelfToAdaptCids);CHKERRQ(ierr);
401*0a96aa3bSJed Brown   ierr            = PetscFree(forest->data);CHKERRQ(ierr);
402*0a96aa3bSJed Brown   PetscFunctionReturn(0);
403*0a96aa3bSJed Brown }
404*0a96aa3bSJed Brown 
405*0a96aa3bSJed Brown #define DMForestTemplate_pforest _append_pforest(DMForestTemplate)
406*0a96aa3bSJed Brown static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm)
407*0a96aa3bSJed Brown {
408*0a96aa3bSJed Brown   DM_Forest_pforest *pforest  = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
409*0a96aa3bSJed Brown   DM_Forest_pforest *tpforest = (DM_Forest_pforest*) ((DM_Forest*) tdm->data)->data;
410*0a96aa3bSJed Brown   PetscErrorCode    ierr;
411*0a96aa3bSJed Brown 
412*0a96aa3bSJed Brown   PetscFunctionBegin;
413*0a96aa3bSJed Brown   if (pforest->topo) pforest->topo->refct++;
414*0a96aa3bSJed Brown   ierr           = DMFTopologyDestroy_pforest(&(tpforest->topo));CHKERRQ(ierr);
415*0a96aa3bSJed Brown   tpforest->topo = pforest->topo;
416*0a96aa3bSJed Brown   PetscFunctionReturn(0);
417*0a96aa3bSJed Brown }
418*0a96aa3bSJed Brown 
419*0a96aa3bSJed Brown #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity)
420*0a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM,p4est_connectivity_t**,PetscInt**);
421*0a96aa3bSJed Brown 
422*0a96aa3bSJed Brown typedef struct _PforestAdaptCtx
423*0a96aa3bSJed Brown {
424*0a96aa3bSJed Brown   PetscInt  maxLevel;
425*0a96aa3bSJed Brown   PetscInt  minLevel;
426*0a96aa3bSJed Brown   PetscInt  currLevel;
427*0a96aa3bSJed Brown   PetscBool anyChange;
428*0a96aa3bSJed Brown }
429*0a96aa3bSJed Brown PforestAdaptCtx;
430*0a96aa3bSJed Brown 
431*0a96aa3bSJed Brown static int pforest_coarsen_currlevel(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
432*0a96aa3bSJed Brown {
433*0a96aa3bSJed Brown   PforestAdaptCtx *ctx      = (PforestAdaptCtx*) p4est->user_pointer;
434*0a96aa3bSJed Brown   PetscInt        minLevel  = ctx->minLevel;
435*0a96aa3bSJed Brown   PetscInt        currLevel = ctx->currLevel;
436*0a96aa3bSJed Brown 
437*0a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
438*0a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level == currLevel);
439*0a96aa3bSJed Brown }
440*0a96aa3bSJed Brown 
441*0a96aa3bSJed Brown static int pforest_coarsen_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
442*0a96aa3bSJed Brown {
443*0a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
444*0a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
445*0a96aa3bSJed Brown 
446*0a96aa3bSJed Brown   return (int) ((PetscInt) quadrants[0]->level > minLevel);
447*0a96aa3bSJed Brown }
448*0a96aa3bSJed Brown 
449*0a96aa3bSJed Brown static int pforest_coarsen_flag_any(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
450*0a96aa3bSJed Brown {
451*0a96aa3bSJed Brown   PetscInt        i;
452*0a96aa3bSJed Brown   PetscBool       any      = PETSC_FALSE;
453*0a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
454*0a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
455*0a96aa3bSJed Brown 
456*0a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
457*0a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
458*0a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) {
459*0a96aa3bSJed Brown       any = PETSC_FALSE;
460*0a96aa3bSJed Brown       break;
461*0a96aa3bSJed Brown     }
462*0a96aa3bSJed Brown     if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) {
463*0a96aa3bSJed Brown       any = PETSC_TRUE;
464*0a96aa3bSJed Brown       break;
465*0a96aa3bSJed Brown     }
466*0a96aa3bSJed Brown   }
467*0a96aa3bSJed Brown   return any ? 1 : 0;
468*0a96aa3bSJed Brown }
469*0a96aa3bSJed Brown 
470*0a96aa3bSJed Brown static int pforest_coarsen_flag_all(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[])
471*0a96aa3bSJed Brown {
472*0a96aa3bSJed Brown   PetscInt        i;
473*0a96aa3bSJed Brown   PetscBool       all      = PETSC_TRUE;
474*0a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
475*0a96aa3bSJed Brown   PetscInt        minLevel = ctx->minLevel;
476*0a96aa3bSJed Brown 
477*0a96aa3bSJed Brown   if (quadrants[0]->level <= minLevel) return 0;
478*0a96aa3bSJed Brown   for (i = 0; i < P4EST_CHILDREN; i++) {
479*0a96aa3bSJed Brown     if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) {
480*0a96aa3bSJed Brown       all = PETSC_FALSE;
481*0a96aa3bSJed Brown       break;
482*0a96aa3bSJed Brown     }
483*0a96aa3bSJed Brown   }
484*0a96aa3bSJed Brown   return all ? 1 : 0;
485*0a96aa3bSJed Brown }
486*0a96aa3bSJed Brown 
487*0a96aa3bSJed Brown static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
488*0a96aa3bSJed Brown {
489*0a96aa3bSJed Brown   quadrant->p.user_int = DM_ADAPT_DETERMINE;
490*0a96aa3bSJed Brown }
491*0a96aa3bSJed Brown 
492*0a96aa3bSJed Brown static int pforest_refine_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
493*0a96aa3bSJed Brown {
494*0a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
495*0a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
496*0a96aa3bSJed Brown 
497*0a96aa3bSJed Brown   return ((PetscInt) quadrant->level < maxLevel);
498*0a96aa3bSJed Brown }
499*0a96aa3bSJed Brown 
500*0a96aa3bSJed Brown static int pforest_refine_flag(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant)
501*0a96aa3bSJed Brown {
502*0a96aa3bSJed Brown   PforestAdaptCtx *ctx     = (PforestAdaptCtx*) p4est->user_pointer;
503*0a96aa3bSJed Brown   PetscInt        maxLevel = ctx->maxLevel;
504*0a96aa3bSJed Brown 
505*0a96aa3bSJed Brown   if ((PetscInt) quadrant->level >= maxLevel) return 0;
506*0a96aa3bSJed Brown 
507*0a96aa3bSJed Brown   return (quadrant->p.user_int == DM_ADAPT_REFINE);
508*0a96aa3bSJed Brown }
509*0a96aa3bSJed Brown 
510*0a96aa3bSJed 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)
511*0a96aa3bSJed Brown {
512*0a96aa3bSJed Brown   PetscMPIInt    rank = p4estFrom->mpirank;
513*0a96aa3bSJed Brown   p4est_topidx_t t;
514*0a96aa3bSJed Brown   PetscInt       toFineLeaves = 0, fromFineLeaves = 0;
515*0a96aa3bSJed Brown 
516*0a96aa3bSJed Brown   PetscFunctionBegin;
517*0a96aa3bSJed Brown   for (t = flt; t <= llt; t++) { /* count roots and leaves */
518*0a96aa3bSJed Brown     p4est_tree_t     *treeFrom  = &(((p4est_tree_t*) p4estFrom->trees->array)[t]);
519*0a96aa3bSJed Brown     p4est_tree_t     *treeTo    = &(((p4est_tree_t*) p4estTo->trees->array)[t]);
520*0a96aa3bSJed Brown     p4est_quadrant_t *firstFrom = &treeFrom->first_desc;
521*0a96aa3bSJed Brown     p4est_quadrant_t *firstTo   = &treeTo->first_desc;
522*0a96aa3bSJed Brown     PetscInt         numFrom    = (PetscInt) treeFrom->quadrants.elem_count;
523*0a96aa3bSJed Brown     PetscInt         numTo      = (PetscInt) treeTo->quadrants.elem_count;
524*0a96aa3bSJed Brown     p4est_quadrant_t *quadsFrom = (p4est_quadrant_t*) treeFrom->quadrants.array;
525*0a96aa3bSJed Brown     p4est_quadrant_t *quadsTo   = (p4est_quadrant_t*) treeTo->quadrants.array;
526*0a96aa3bSJed Brown     PetscInt         currentFrom, currentTo;
527*0a96aa3bSJed Brown     PetscInt         treeOffsetFrom = (PetscInt) treeFrom->quadrants_offset;
528*0a96aa3bSJed Brown     PetscInt         treeOffsetTo   = (PetscInt) treeTo->quadrants_offset;
529*0a96aa3bSJed Brown     int              comp;
530*0a96aa3bSJed Brown 
531*0a96aa3bSJed Brown     PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(firstFrom,firstTo));
532*0a96aa3bSJed Brown     if (!comp) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"non-matching partitions");
533*0a96aa3bSJed Brown 
534*0a96aa3bSJed Brown     for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) {
535*0a96aa3bSJed Brown       p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom];
536*0a96aa3bSJed Brown       p4est_quadrant_t *quadTo   = &quadsTo[currentTo];
537*0a96aa3bSJed Brown 
538*0a96aa3bSJed Brown       if (quadFrom->level == quadTo->level) {
539*0a96aa3bSJed Brown         if (toLeaves) {
540*0a96aa3bSJed Brown           toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
541*0a96aa3bSJed Brown           fromRoots[toFineLeaves].rank  = rank;
542*0a96aa3bSJed Brown           fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
543*0a96aa3bSJed Brown         }
544*0a96aa3bSJed Brown         toFineLeaves++;
545*0a96aa3bSJed Brown         currentFrom++;
546*0a96aa3bSJed Brown         currentTo++;
547*0a96aa3bSJed Brown       } else {
548*0a96aa3bSJed Brown         int fromIsAncestor;
549*0a96aa3bSJed Brown 
550*0a96aa3bSJed Brown         PetscStackCallP4estReturn(fromIsAncestor,p4est_quadrant_is_ancestor,(quadFrom,quadTo));
551*0a96aa3bSJed Brown         if (fromIsAncestor) {
552*0a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
553*0a96aa3bSJed Brown 
554*0a96aa3bSJed Brown           if (toLeaves) {
555*0a96aa3bSJed Brown             toLeaves[toFineLeaves]        = currentTo + treeOffsetTo + ToOffset;
556*0a96aa3bSJed Brown             fromRoots[toFineLeaves].rank  = rank;
557*0a96aa3bSJed Brown             fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset;
558*0a96aa3bSJed Brown           }
559*0a96aa3bSJed Brown           toFineLeaves++;
560*0a96aa3bSJed Brown           currentTo++;
561*0a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadFrom,&lastDesc,quadTo->level));
562*0a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadTo,&lastDesc));
563*0a96aa3bSJed Brown           if (comp) currentFrom++;
564*0a96aa3bSJed Brown         } else {
565*0a96aa3bSJed Brown           p4est_quadrant_t lastDesc;
566*0a96aa3bSJed Brown 
567*0a96aa3bSJed Brown           if (fromLeaves) {
568*0a96aa3bSJed Brown             fromLeaves[fromFineLeaves]    = currentFrom + treeOffsetFrom + FromOffset;
569*0a96aa3bSJed Brown             toRoots[fromFineLeaves].rank  = rank;
570*0a96aa3bSJed Brown             toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset;
571*0a96aa3bSJed Brown           }
572*0a96aa3bSJed Brown           fromFineLeaves++;
573*0a96aa3bSJed Brown           currentFrom++;
574*0a96aa3bSJed Brown           PetscStackCallP4est(p4est_quadrant_last_descendant,(quadTo,&lastDesc,quadFrom->level));
575*0a96aa3bSJed Brown           PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadFrom,&lastDesc));
576*0a96aa3bSJed Brown           if (comp) currentTo++;
577*0a96aa3bSJed Brown         }
578*0a96aa3bSJed Brown       }
579*0a96aa3bSJed Brown     }
580*0a96aa3bSJed Brown   }
581*0a96aa3bSJed Brown   *toFineLeavesCount   = toFineLeaves;
582*0a96aa3bSJed Brown   *fromFineLeavesCount = fromFineLeaves;
583*0a96aa3bSJed Brown   PetscFunctionReturn(0);
584*0a96aa3bSJed Brown }
585*0a96aa3bSJed Brown 
586*0a96aa3bSJed Brown /* Compute the maximum level across all the trees */
587*0a96aa3bSJed Brown static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev)
588*0a96aa3bSJed Brown {
589*0a96aa3bSJed Brown   p4est_topidx_t    t, flt, llt;
590*0a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
591*0a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
592*0a96aa3bSJed Brown   PetscInt          maxlevelloc = 0;
593*0a96aa3bSJed Brown   p4est_t           *p4est;
594*0a96aa3bSJed Brown   PetscErrorCode    ierr;
595*0a96aa3bSJed Brown 
596*0a96aa3bSJed Brown   PetscFunctionBegin;
597*0a96aa3bSJed Brown   if (!pforest) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing DM_Forest_pforest");
598*0a96aa3bSJed Brown   if (!pforest->forest) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing p4est_t");
599*0a96aa3bSJed Brown   p4est = pforest->forest;
600*0a96aa3bSJed Brown   flt   = p4est->first_local_tree;
601*0a96aa3bSJed Brown   llt   = p4est->last_local_tree;
602*0a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
603*0a96aa3bSJed Brown     p4est_tree_t *tree  = &(((p4est_tree_t*) p4est->trees->array)[t]);
604*0a96aa3bSJed Brown     maxlevelloc = PetscMax((PetscInt)tree->maxlevel,maxlevelloc);
605*0a96aa3bSJed Brown   }
606*0a96aa3bSJed Brown   ierr = MPIU_Allreduce(&maxlevelloc,lev,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
607*0a96aa3bSJed Brown   PetscFunctionReturn(0);
608*0a96aa3bSJed Brown }
609*0a96aa3bSJed Brown 
610*0a96aa3bSJed Brown /* Puts identity in coarseToFine */
611*0a96aa3bSJed Brown /* assumes a matching partition */
612*0a96aa3bSJed Brown static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine)
613*0a96aa3bSJed Brown {
614*0a96aa3bSJed Brown   p4est_topidx_t flt, llt;
615*0a96aa3bSJed Brown   PetscSF        fromCoarse, toCoarse;
616*0a96aa3bSJed Brown   PetscInt       numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo;
617*0a96aa3bSJed Brown   PetscInt       *fromLeaves = NULL, *toLeaves = NULL;
618*0a96aa3bSJed Brown   PetscSFNode    *fromRoots  = NULL, *toRoots = NULL;
619*0a96aa3bSJed Brown   PetscErrorCode ierr;
620*0a96aa3bSJed Brown 
621*0a96aa3bSJed Brown   PetscFunctionBegin;
622*0a96aa3bSJed Brown   flt  = p4estFrom->first_local_tree;
623*0a96aa3bSJed Brown   llt  = p4estFrom->last_local_tree;
624*0a96aa3bSJed Brown   ierr = PetscSFCreate(comm,&fromCoarse);CHKERRQ(ierr);
625*0a96aa3bSJed Brown   if (toCoarseFromFine) {
626*0a96aa3bSJed Brown     ierr = PetscSFCreate(comm,&toCoarse);CHKERRQ(ierr);
627*0a96aa3bSJed Brown   }
628*0a96aa3bSJed Brown   numRootsFrom = p4estFrom->local_num_quadrants + FromOffset;
629*0a96aa3bSJed Brown   numRootsTo   = p4estTo->local_num_quadrants + ToOffset;
630*0a96aa3bSJed Brown   ierr         = DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,NULL,NULL,&numLeavesFrom,NULL,NULL);CHKERRQ(ierr);
631*0a96aa3bSJed Brown   ierr         = PetscMalloc1(numLeavesTo,&toLeaves);CHKERRQ(ierr);
632*0a96aa3bSJed Brown   ierr         = PetscMalloc1(numLeavesTo,&fromRoots);CHKERRQ(ierr);
633*0a96aa3bSJed Brown   if (toCoarseFromFine) {
634*0a96aa3bSJed Brown     ierr = PetscMalloc1(numLeavesFrom,&fromLeaves);CHKERRQ(ierr);
635*0a96aa3bSJed Brown     ierr = PetscMalloc1(numLeavesFrom,&fromRoots);CHKERRQ(ierr);
636*0a96aa3bSJed Brown   }
637*0a96aa3bSJed Brown   ierr = DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,toLeaves,fromRoots,&numLeavesFrom,fromLeaves,toRoots);CHKERRQ(ierr);
638*0a96aa3bSJed Brown   if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */
639*0a96aa3bSJed Brown     ierr = PetscFree(toLeaves);CHKERRQ(ierr);
640*0a96aa3bSJed Brown     ierr = PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,NULL,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER);CHKERRQ(ierr);
641*0a96aa3bSJed Brown   } else { /* generic */
642*0a96aa3bSJed Brown     ierr = PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,toLeaves,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER);CHKERRQ(ierr);
643*0a96aa3bSJed Brown   }
644*0a96aa3bSJed Brown   *fromCoarseToFine = fromCoarse;
645*0a96aa3bSJed Brown   if (toCoarseFromFine) {
646*0a96aa3bSJed Brown     ierr              = PetscSFSetGraph(toCoarse,numRootsTo,numLeavesFrom,fromLeaves,PETSC_OWN_POINTER,toRoots,PETSC_OWN_POINTER);CHKERRQ(ierr);
647*0a96aa3bSJed Brown     *toCoarseFromFine = toCoarse;
648*0a96aa3bSJed Brown   }
649*0a96aa3bSJed Brown   PetscFunctionReturn(0);
650*0a96aa3bSJed Brown }
651*0a96aa3bSJed Brown 
652*0a96aa3bSJed Brown /* range of processes whose B sections overlap this ranks A section */
653*0a96aa3bSJed Brown static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB)
654*0a96aa3bSJed Brown {
655*0a96aa3bSJed Brown   p4est_quadrant_t * myCoarseStart = &(p4estA->global_first_position[rank]);
656*0a96aa3bSJed Brown   p4est_quadrant_t * myCoarseEnd   = &(p4estA->global_first_position[rank+1]);
657*0a96aa3bSJed Brown   p4est_quadrant_t * globalFirstB  = p4estB->global_first_position;
658*0a96aa3bSJed Brown 
659*0a96aa3bSJed Brown   PetscFunctionBegin;
660*0a96aa3bSJed Brown   *startB = -1;
661*0a96aa3bSJed Brown   *endB   = -1;
662*0a96aa3bSJed Brown   if (p4estA->local_num_quadrants) {
663*0a96aa3bSJed Brown     PetscInt lo, hi, guess;
664*0a96aa3bSJed Brown     /* binary search to find interval containing myCoarseStart */
665*0a96aa3bSJed Brown     lo    = 0;
666*0a96aa3bSJed Brown     hi    = size;
667*0a96aa3bSJed Brown     guess = rank;
668*0a96aa3bSJed Brown     while (1) {
669*0a96aa3bSJed Brown       int startCompMy, myCompEnd;
670*0a96aa3bSJed Brown 
671*0a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseStart));
672*0a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseStart,&globalFirstB[guess+1]));
673*0a96aa3bSJed Brown       if (startCompMy <= 0 && myCompEnd < 0) {
674*0a96aa3bSJed Brown         *startB = guess;
675*0a96aa3bSJed Brown         break;
676*0a96aa3bSJed Brown       } else if (startCompMy > 0) {  /* guess is to high */
677*0a96aa3bSJed Brown         hi = guess;
678*0a96aa3bSJed Brown       } else { /* guess is to low */
679*0a96aa3bSJed Brown         lo = guess + 1;
680*0a96aa3bSJed Brown       }
681*0a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
682*0a96aa3bSJed Brown     }
683*0a96aa3bSJed Brown     /* reset bounds, but not guess */
684*0a96aa3bSJed Brown     lo = 0;
685*0a96aa3bSJed Brown     hi = size;
686*0a96aa3bSJed Brown     while (1) {
687*0a96aa3bSJed Brown       int startCompMy, myCompEnd;
688*0a96aa3bSJed Brown 
689*0a96aa3bSJed Brown       PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseEnd));
690*0a96aa3bSJed Brown       PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseEnd,&globalFirstB[guess+1]));
691*0a96aa3bSJed Brown       if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */
692*0a96aa3bSJed Brown         *endB = guess + 1;
693*0a96aa3bSJed Brown         break;
694*0a96aa3bSJed Brown       } else if (startCompMy >= 0) { /* guess is to high */
695*0a96aa3bSJed Brown         hi = guess;
696*0a96aa3bSJed Brown       } else { /* guess is to low */
697*0a96aa3bSJed Brown         lo = guess + 1;
698*0a96aa3bSJed Brown       }
699*0a96aa3bSJed Brown       guess = lo + (hi - lo) / 2;
700*0a96aa3bSJed Brown     }
701*0a96aa3bSJed Brown   }
702*0a96aa3bSJed Brown   PetscFunctionReturn(0);
703*0a96aa3bSJed Brown }
704*0a96aa3bSJed Brown 
705*0a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM,DM*);
706*0a96aa3bSJed Brown 
707*0a96aa3bSJed Brown #define DMSetUp_pforest _append_pforest(DMSetUp)
708*0a96aa3bSJed Brown static PetscErrorCode DMSetUp_pforest(DM dm)
709*0a96aa3bSJed Brown {
710*0a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
711*0a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
712*0a96aa3bSJed Brown   DM                base, adaptFrom;
713*0a96aa3bSJed Brown   DMForestTopology  topoName;
714*0a96aa3bSJed Brown   PetscSF           preCoarseToFine = NULL, coarseToPreFine = NULL;
715*0a96aa3bSJed Brown   PforestAdaptCtx   ctx;
716*0a96aa3bSJed Brown   PetscErrorCode    ierr;
717*0a96aa3bSJed Brown 
718*0a96aa3bSJed Brown   PetscFunctionBegin;
719*0a96aa3bSJed Brown   ctx.minLevel  = PETSC_MAX_INT;
720*0a96aa3bSJed Brown   ctx.maxLevel  = 0;
721*0a96aa3bSJed Brown   ctx.currLevel = 0;
722*0a96aa3bSJed Brown   ctx.anyChange = PETSC_FALSE;
723*0a96aa3bSJed Brown   /* sanity check */
724*0a96aa3bSJed Brown   ierr = DMForestGetAdaptivityForest(dm,&adaptFrom);CHKERRQ(ierr);
725*0a96aa3bSJed Brown   ierr = DMForestGetBaseDM(dm,&base);CHKERRQ(ierr);
726*0a96aa3bSJed Brown   ierr = DMForestGetTopology(dm,&topoName);CHKERRQ(ierr);
727*0a96aa3bSJed Brown   if (!adaptFrom && !base && !topoName) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"A forest needs a topology, a base DM, or a DM to adapt from");
728*0a96aa3bSJed Brown 
729*0a96aa3bSJed Brown   /* === Step 1: DMFTopology === */
730*0a96aa3bSJed Brown   if (adaptFrom) { /* reference already created topology */
731*0a96aa3bSJed Brown     PetscBool         ispforest;
732*0a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
733*0a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
734*0a96aa3bSJed Brown 
735*0a96aa3bSJed Brown     ierr = PetscObjectTypeCompare((PetscObject)adaptFrom,DMPFOREST,&ispforest);CHKERRQ(ierr);
736*0a96aa3bSJed Brown     if (!ispforest) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Trying to adapt from %s, which is not %s",((PetscObject)adaptFrom)->type_name,DMPFOREST);
737*0a96aa3bSJed Brown     if (!apforest->topo) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"The pre-adaptation forest must have a topology");
738*0a96aa3bSJed Brown     ierr = DMSetUp(adaptFrom);CHKERRQ(ierr);
739*0a96aa3bSJed Brown     ierr = DMForestGetBaseDM(dm,&base);CHKERRQ(ierr);
740*0a96aa3bSJed Brown     ierr = DMForestGetTopology(dm,&topoName);CHKERRQ(ierr);
741*0a96aa3bSJed Brown   } else if (base) { /* construct a connectivity from base */
742*0a96aa3bSJed Brown     PetscBool isPlex, isDA;
743*0a96aa3bSJed Brown 
744*0a96aa3bSJed Brown     ierr = PetscObjectGetName((PetscObject)base,&topoName);CHKERRQ(ierr);
745*0a96aa3bSJed Brown     ierr = DMForestSetTopology(dm,topoName);CHKERRQ(ierr);
746*0a96aa3bSJed Brown     ierr = PetscObjectTypeCompare((PetscObject)base,DMPLEX,&isPlex);CHKERRQ(ierr);
747*0a96aa3bSJed Brown     ierr = PetscObjectTypeCompare((PetscObject)base,DMDA,&isDA);CHKERRQ(ierr);
748*0a96aa3bSJed Brown     if (isPlex) {
749*0a96aa3bSJed Brown       MPI_Comm             comm = PetscObjectComm((PetscObject)dm);
750*0a96aa3bSJed Brown       PetscInt             depth;
751*0a96aa3bSJed Brown       PetscMPIInt          size;
752*0a96aa3bSJed Brown       p4est_connectivity_t *conn = NULL;
753*0a96aa3bSJed Brown       DMFTopology_pforest  *topo;
754*0a96aa3bSJed Brown       PetscInt             *tree_face_to_uniq = NULL;
755*0a96aa3bSJed Brown       PetscErrorCode       ierr;
756*0a96aa3bSJed Brown 
757*0a96aa3bSJed Brown       ierr = DMPlexGetDepth(base,&depth);CHKERRQ(ierr);
758*0a96aa3bSJed Brown       if (depth == 1) {
759*0a96aa3bSJed Brown         DM connDM;
760*0a96aa3bSJed Brown 
761*0a96aa3bSJed Brown         ierr = DMPlexInterpolate(base,&connDM);CHKERRQ(ierr);
762*0a96aa3bSJed Brown         base = connDM;
763*0a96aa3bSJed Brown         ierr = DMForestSetBaseDM(dm,base);CHKERRQ(ierr);
764*0a96aa3bSJed Brown         ierr = DMDestroy(&connDM);CHKERRQ(ierr);
765*0a96aa3bSJed Brown       } else if (depth != P4EST_DIM) SETERRQ2(comm,PETSC_ERR_ARG_WRONG,"Base plex is neither interpolated nor uninterpolated? depth %D, expected 2 or %d",depth,P4EST_DIM + 1);
766*0a96aa3bSJed Brown       ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
767*0a96aa3bSJed Brown       if (size > 1) {
768*0a96aa3bSJed Brown         DM      dmRedundant;
769*0a96aa3bSJed Brown         PetscSF sf;
770*0a96aa3bSJed Brown 
771*0a96aa3bSJed Brown         ierr = DMPlexGetRedundantDM(base,&sf,&dmRedundant);CHKERRQ(ierr);
772*0a96aa3bSJed Brown         if (!dmRedundant) SETERRQ(comm,PETSC_ERR_PLIB,"Could not create redundant DM");
773*0a96aa3bSJed Brown         ierr = PetscObjectCompose((PetscObject)dmRedundant,"_base_migration_sf",(PetscObject)sf);CHKERRQ(ierr);
774*0a96aa3bSJed Brown         ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
775*0a96aa3bSJed Brown         base = dmRedundant;
776*0a96aa3bSJed Brown         ierr = DMForestSetBaseDM(dm,base);CHKERRQ(ierr);
777*0a96aa3bSJed Brown         ierr = DMDestroy(&dmRedundant);CHKERRQ(ierr);
778*0a96aa3bSJed Brown       }
779*0a96aa3bSJed Brown       ierr        = DMViewFromOptions(base,NULL,"-dm_p4est_base_view");CHKERRQ(ierr);
780*0a96aa3bSJed Brown       ierr        = DMPlexCreateConnectivity_pforest(base,&conn,&tree_face_to_uniq);CHKERRQ(ierr);
781*0a96aa3bSJed Brown       ierr        = PetscNewLog(dm,&topo);CHKERRQ(ierr);
782*0a96aa3bSJed Brown       topo->refct = 1;
783*0a96aa3bSJed Brown       topo->conn  = conn;
784*0a96aa3bSJed Brown       topo->geom  = NULL;
785*0a96aa3bSJed Brown       {
786*0a96aa3bSJed Brown         PetscErrorCode (*map)(DM,PetscInt,PetscInt,const PetscReal[],PetscReal[],void*);
787*0a96aa3bSJed Brown         void           *mapCtx;
788*0a96aa3bSJed Brown 
789*0a96aa3bSJed Brown         ierr = DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx);CHKERRQ(ierr);
790*0a96aa3bSJed Brown         if (map) {
791*0a96aa3bSJed Brown           DM_Forest_geometry_pforest *geom_pforest;
792*0a96aa3bSJed Brown           p4est_geometry_t           *geom;
793*0a96aa3bSJed Brown 
794*0a96aa3bSJed Brown           ierr                 = PetscNew(&geom_pforest);CHKERRQ(ierr);
795*0a96aa3bSJed Brown           ierr                 = DMGetCoordinateDim(dm,&geom_pforest->coordDim);CHKERRQ(ierr);
796*0a96aa3bSJed Brown           geom_pforest->map    = map;
797*0a96aa3bSJed Brown           geom_pforest->mapCtx = mapCtx;
798*0a96aa3bSJed Brown           PetscStackCallP4estReturn(geom_pforest->inner,p4est_geometry_new_connectivity,(conn));
799*0a96aa3bSJed Brown           ierr          = PetscNew(&geom);CHKERRQ(ierr);
800*0a96aa3bSJed Brown           geom->name    = topoName;
801*0a96aa3bSJed Brown           geom->user    = geom_pforest;
802*0a96aa3bSJed Brown           geom->X       = GeometryMapping_pforest;
803*0a96aa3bSJed Brown           geom->destroy = GeometryDestroy_pforest;
804*0a96aa3bSJed Brown           topo->geom    = geom;
805*0a96aa3bSJed Brown         }
806*0a96aa3bSJed Brown       }
807*0a96aa3bSJed Brown       topo->tree_face_to_uniq = tree_face_to_uniq;
808*0a96aa3bSJed Brown       pforest->topo           = topo;
809*0a96aa3bSJed Brown     } else if (isDA) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Not implemented yet");
810*0a96aa3bSJed Brown #if 0
811*0a96aa3bSJed Brown       PetscInt N[3], P[3];
812*0a96aa3bSJed Brown 
813*0a96aa3bSJed Brown       /* get the sizes, periodicities */
814*0a96aa3bSJed Brown       /* ... */
815*0a96aa3bSJed Brown                                                                   /* don't use Morton order */
816*0a96aa3bSJed Brown       ierr = DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE);CHKERRQ(ierr);
817*0a96aa3bSJed Brown #endif
818*0a96aa3bSJed Brown     {
819*0a96aa3bSJed Brown       PetscInt numLabels, l;
820*0a96aa3bSJed Brown 
821*0a96aa3bSJed Brown       ierr = DMGetNumLabels(base,&numLabels);CHKERRQ(ierr);
822*0a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
823*0a96aa3bSJed Brown         PetscBool  isDepth, isGhost, isVTK, isDim, isCellType;
824*0a96aa3bSJed Brown         DMLabel    label, labelNew;
825*0a96aa3bSJed Brown         PetscInt   defVal;
826*0a96aa3bSJed Brown         const char *name;
827*0a96aa3bSJed Brown 
828*0a96aa3bSJed Brown         ierr = DMGetLabelName(base, l, &name);CHKERRQ(ierr);
829*0a96aa3bSJed Brown         ierr = DMGetLabelByNum(base, l, &label);CHKERRQ(ierr);
830*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"depth",&isDepth);CHKERRQ(ierr);
831*0a96aa3bSJed Brown         if (isDepth) continue;
832*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"dim",&isDim);CHKERRQ(ierr);
833*0a96aa3bSJed Brown         if (isDim) continue;
834*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"celltype",&isCellType);CHKERRQ(ierr);
835*0a96aa3bSJed Brown         if (isCellType) continue;
836*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"ghost",&isGhost);CHKERRQ(ierr);
837*0a96aa3bSJed Brown         if (isGhost) continue;
838*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"vtk",&isVTK);CHKERRQ(ierr);
839*0a96aa3bSJed Brown         if (isVTK) continue;
840*0a96aa3bSJed Brown         ierr = DMCreateLabel(dm,name);CHKERRQ(ierr);
841*0a96aa3bSJed Brown         ierr = DMGetLabel(dm,name,&labelNew);CHKERRQ(ierr);
842*0a96aa3bSJed Brown         ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
843*0a96aa3bSJed Brown         ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
844*0a96aa3bSJed Brown       }
845*0a96aa3bSJed Brown       /* map dm points (internal plex) to base
846*0a96aa3bSJed Brown          we currently create the subpoint_map for the entire hierarchy, starting from the finest forest
847*0a96aa3bSJed Brown          and propagating back to the coarsest
848*0a96aa3bSJed Brown          This is not an optimal approach, since we need the map only on the coarsest level
849*0a96aa3bSJed Brown          during DMForestTransferVecFromBase */
850*0a96aa3bSJed Brown       ierr = DMForestGetMinimumRefinement(dm,&l);CHKERRQ(ierr);
851*0a96aa3bSJed Brown       if (!l) {
852*0a96aa3bSJed Brown         ierr = DMCreateLabel(dm,"_forest_base_subpoint_map");CHKERRQ(ierr);
853*0a96aa3bSJed Brown       }
854*0a96aa3bSJed Brown     }
855*0a96aa3bSJed Brown   } else { /* construct from topology name */
856*0a96aa3bSJed Brown     DMFTopology_pforest *topo;
857*0a96aa3bSJed Brown 
858*0a96aa3bSJed Brown     ierr          = DMFTopologyCreate_pforest(dm,topoName,&topo);CHKERRQ(ierr);
859*0a96aa3bSJed Brown     pforest->topo = topo;
860*0a96aa3bSJed Brown     /* TODO: construct base? */
861*0a96aa3bSJed Brown   }
862*0a96aa3bSJed Brown 
863*0a96aa3bSJed Brown   /* === Step 2: get the leaves of the forest === */
864*0a96aa3bSJed Brown   if (adaptFrom) { /* start with the old forest */
865*0a96aa3bSJed Brown     DMLabel           adaptLabel;
866*0a96aa3bSJed Brown     PetscInt          defaultValue;
867*0a96aa3bSJed Brown     PetscInt          numValues, numValuesGlobal, cLocalStart, count;
868*0a96aa3bSJed Brown     DM_Forest         *aforest  = (DM_Forest*) adaptFrom->data;
869*0a96aa3bSJed Brown     DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data;
870*0a96aa3bSJed Brown     PetscBool         computeAdaptSF;
871*0a96aa3bSJed Brown     p4est_topidx_t    flt, llt, t;
872*0a96aa3bSJed Brown 
873*0a96aa3bSJed Brown     flt         = apforest->forest->first_local_tree;
874*0a96aa3bSJed Brown     llt         = apforest->forest->last_local_tree;
875*0a96aa3bSJed Brown     cLocalStart = apforest->cLocalStart;
876*0a96aa3bSJed Brown     ierr = DMForestGetComputeAdaptivitySF(dm,&computeAdaptSF);CHKERRQ(ierr);
877*0a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_copy,(apforest->forest, 0)); /* 0 indicates no data copying */
878*0a96aa3bSJed Brown     ierr = DMForestGetAdaptivityLabel(dm,&adaptLabel);CHKERRQ(ierr);
879*0a96aa3bSJed Brown     if (adaptLabel) {
880*0a96aa3bSJed Brown       /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */
881*0a96aa3bSJed Brown       ierr = DMLabelGetNumValues(adaptLabel,&numValues);CHKERRQ(ierr);
882*0a96aa3bSJed Brown       ierr = MPI_Allreduce(&numValues,&numValuesGlobal,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)adaptFrom));CHKERRMPI(ierr);
883*0a96aa3bSJed Brown       ierr = DMLabelGetDefaultValue(adaptLabel,&defaultValue);CHKERRQ(ierr);
884*0a96aa3bSJed Brown       if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids)  */
885*0a96aa3bSJed Brown         ierr                          = DMForestGetMinimumRefinement(dm,&ctx.minLevel);CHKERRQ(ierr);
886*0a96aa3bSJed Brown         ierr                          = DMPforestGetRefinementLevel(dm,&ctx.currLevel);CHKERRQ(ierr);
887*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
888*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_currlevel,NULL));
889*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
890*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
891*0a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
892*0a96aa3bSJed Brown         if (computeAdaptSF) {
893*0a96aa3bSJed Brown           ierr = DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL);CHKERRQ(ierr);
894*0a96aa3bSJed Brown         }
895*0a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */
896*0a96aa3bSJed Brown         ierr                          = DMForestGetMinimumRefinement(dm,&ctx.minLevel);CHKERRQ(ierr);
897*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
898*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_uniform,NULL));
899*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
900*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
901*0a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
902*0a96aa3bSJed Brown         if (computeAdaptSF) {
903*0a96aa3bSJed Brown           ierr = DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL);CHKERRQ(ierr);
904*0a96aa3bSJed Brown         }
905*0a96aa3bSJed Brown       } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */
906*0a96aa3bSJed Brown         ierr                          = DMForestGetMaximumRefinement(dm,&ctx.maxLevel);CHKERRQ(ierr);
907*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
908*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_uniform,NULL));
909*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
910*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
911*0a96aa3bSJed Brown         /* we will have to change the offset after we compute the overlap */
912*0a96aa3bSJed Brown         if (computeAdaptSF) {
913*0a96aa3bSJed Brown           ierr = DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,NULL);CHKERRQ(ierr);
914*0a96aa3bSJed Brown         }
915*0a96aa3bSJed Brown       } else if (numValuesGlobal) {
916*0a96aa3bSJed Brown         p4est_t                    *p4est = pforest->forest;
917*0a96aa3bSJed Brown         PetscInt                   *cellFlags;
918*0a96aa3bSJed Brown         DMForestAdaptivityStrategy strategy;
919*0a96aa3bSJed Brown         PetscSF                    cellSF;
920*0a96aa3bSJed Brown         PetscInt                   c, cStart, cEnd;
921*0a96aa3bSJed Brown         PetscBool                  adaptAny;
922*0a96aa3bSJed Brown 
923*0a96aa3bSJed Brown         ierr = DMForestGetMaximumRefinement(dm,&ctx.maxLevel);CHKERRQ(ierr);
924*0a96aa3bSJed Brown         ierr = DMForestGetMinimumRefinement(dm,&ctx.minLevel);CHKERRQ(ierr);
925*0a96aa3bSJed Brown         ierr = DMForestGetAdaptivityStrategy(dm,&strategy);CHKERRQ(ierr);
926*0a96aa3bSJed Brown         ierr = PetscStrncmp(strategy,"any",3,&adaptAny);CHKERRQ(ierr);
927*0a96aa3bSJed Brown         ierr = DMForestGetCellChart(adaptFrom,&cStart,&cEnd);CHKERRQ(ierr);
928*0a96aa3bSJed Brown         ierr = DMForestGetCellSF(adaptFrom,&cellSF);CHKERRQ(ierr);
929*0a96aa3bSJed Brown         ierr = PetscMalloc1(cEnd-cStart,&cellFlags);CHKERRQ(ierr);
930*0a96aa3bSJed Brown         for (c = cStart; c < cEnd; c++) {ierr = DMLabelGetValue(adaptLabel,c,&cellFlags[c-cStart]);CHKERRQ(ierr);}
931*0a96aa3bSJed Brown         if (cellSF) {
932*0a96aa3bSJed Brown           if (adaptAny) {
933*0a96aa3bSJed Brown             ierr = PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX);CHKERRQ(ierr);
934*0a96aa3bSJed Brown             ierr = PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX);CHKERRQ(ierr);
935*0a96aa3bSJed Brown           } else {
936*0a96aa3bSJed Brown             ierr = PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN);CHKERRQ(ierr);
937*0a96aa3bSJed Brown             ierr = PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN);CHKERRQ(ierr);
938*0a96aa3bSJed Brown           }
939*0a96aa3bSJed Brown         }
940*0a96aa3bSJed Brown         for (t = flt, count = cLocalStart; t <= llt; t++) {
941*0a96aa3bSJed Brown           p4est_tree_t       *tree    = &(((p4est_tree_t*) p4est->trees->array)[t]);
942*0a96aa3bSJed Brown           PetscInt           numQuads = (PetscInt) tree->quadrants.elem_count, i;
943*0a96aa3bSJed Brown           p4est_quadrant_t   *quads   = (p4est_quadrant_t *) tree->quadrants.array;
944*0a96aa3bSJed Brown 
945*0a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
946*0a96aa3bSJed Brown             p4est_quadrant_t *q = &quads[i];
947*0a96aa3bSJed Brown             q->p.user_int = cellFlags[count++];
948*0a96aa3bSJed Brown           }
949*0a96aa3bSJed Brown         }
950*0a96aa3bSJed Brown         ierr = PetscFree(cellFlags);CHKERRQ(ierr);
951*0a96aa3bSJed Brown 
952*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) &ctx;
953*0a96aa3bSJed Brown         if (adaptAny) {
954*0a96aa3bSJed Brown           PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_any,pforest_init_determine));
955*0a96aa3bSJed Brown         } else {
956*0a96aa3bSJed Brown           PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_all,pforest_init_determine));
957*0a96aa3bSJed Brown         }
958*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_flag,NULL));
959*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
960*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
961*0a96aa3bSJed Brown         if (computeAdaptSF) {
962*0a96aa3bSJed Brown           ierr = DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,&coarseToPreFine);CHKERRQ(ierr);
963*0a96aa3bSJed Brown         }
964*0a96aa3bSJed Brown       }
965*0a96aa3bSJed Brown       for (t = flt, count = cLocalStart; t <= llt; t++) {
966*0a96aa3bSJed Brown         p4est_tree_t       *atree    = &(((p4est_tree_t*) apforest->forest->trees->array)[t]);
967*0a96aa3bSJed Brown         p4est_tree_t       *tree     = &(((p4est_tree_t*) pforest->forest->trees->array)[t]);
968*0a96aa3bSJed Brown         PetscInt           anumQuads = (PetscInt) atree->quadrants.elem_count, i;
969*0a96aa3bSJed Brown         PetscInt           numQuads  = (PetscInt) tree->quadrants.elem_count;
970*0a96aa3bSJed Brown         p4est_quadrant_t   *aquads   = (p4est_quadrant_t *) atree->quadrants.array;
971*0a96aa3bSJed Brown         p4est_quadrant_t   *quads    = (p4est_quadrant_t *) tree->quadrants.array;
972*0a96aa3bSJed Brown 
973*0a96aa3bSJed Brown         if (anumQuads != numQuads) {
974*0a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
975*0a96aa3bSJed Brown         } else {
976*0a96aa3bSJed Brown           for (i = 0; i < numQuads; i++) {
977*0a96aa3bSJed Brown             p4est_quadrant_t *aq = &aquads[i];
978*0a96aa3bSJed Brown             p4est_quadrant_t *q  = &quads[i];
979*0a96aa3bSJed Brown 
980*0a96aa3bSJed Brown             if (aq->level != q->level) {
981*0a96aa3bSJed Brown               ctx.anyChange = PETSC_TRUE;
982*0a96aa3bSJed Brown               break;
983*0a96aa3bSJed Brown             }
984*0a96aa3bSJed Brown           }
985*0a96aa3bSJed Brown         }
986*0a96aa3bSJed Brown         if (ctx.anyChange) {
987*0a96aa3bSJed Brown           break;
988*0a96aa3bSJed Brown         }
989*0a96aa3bSJed Brown       }
990*0a96aa3bSJed Brown     }
991*0a96aa3bSJed Brown     {
992*0a96aa3bSJed Brown       PetscInt numLabels, l;
993*0a96aa3bSJed Brown 
994*0a96aa3bSJed Brown       ierr = DMGetNumLabels(adaptFrom,&numLabels);CHKERRQ(ierr);
995*0a96aa3bSJed Brown       for (l = 0; l < numLabels; l++) {
996*0a96aa3bSJed Brown         PetscBool  isDepth, isCellType, isGhost, isVTK;
997*0a96aa3bSJed Brown         DMLabel    label, labelNew;
998*0a96aa3bSJed Brown         PetscInt   defVal;
999*0a96aa3bSJed Brown         const char *name;
1000*0a96aa3bSJed Brown 
1001*0a96aa3bSJed Brown         ierr = DMGetLabelName(adaptFrom, l, &name);CHKERRQ(ierr);
1002*0a96aa3bSJed Brown         ierr = DMGetLabelByNum(adaptFrom, l, &label);CHKERRQ(ierr);
1003*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"depth",&isDepth);CHKERRQ(ierr);
1004*0a96aa3bSJed Brown         if (isDepth) continue;
1005*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"celltype",&isCellType);CHKERRQ(ierr);
1006*0a96aa3bSJed Brown         if (isCellType) continue;
1007*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"ghost",&isGhost);CHKERRQ(ierr);
1008*0a96aa3bSJed Brown         if (isGhost) continue;
1009*0a96aa3bSJed Brown         ierr = PetscStrcmp(name,"vtk",&isVTK);CHKERRQ(ierr);
1010*0a96aa3bSJed Brown         if (isVTK) continue;
1011*0a96aa3bSJed Brown         ierr = DMCreateLabel(dm,name);CHKERRQ(ierr);
1012*0a96aa3bSJed Brown         ierr = DMGetLabel(dm,name,&labelNew);CHKERRQ(ierr);
1013*0a96aa3bSJed Brown         ierr = DMLabelGetDefaultValue(label,&defVal);CHKERRQ(ierr);
1014*0a96aa3bSJed Brown         ierr = DMLabelSetDefaultValue(labelNew,defVal);CHKERRQ(ierr);
1015*0a96aa3bSJed Brown       }
1016*0a96aa3bSJed Brown     }
1017*0a96aa3bSJed Brown   } else { /* initial */
1018*0a96aa3bSJed Brown     PetscInt initLevel, minLevel;
1019*0a96aa3bSJed Brown 
1020*0a96aa3bSJed Brown     ierr = DMForestGetInitialRefinement(dm,&initLevel);CHKERRQ(ierr);
1021*0a96aa3bSJed Brown     ierr = DMForestGetMinimumRefinement(dm,&minLevel);CHKERRQ(ierr);
1022*0a96aa3bSJed Brown     PetscStackCallP4estReturn(pforest->forest,p4est_new_ext,(PetscObjectComm((PetscObject)dm),pforest->topo->conn,
1023*0a96aa3bSJed Brown                                                              0,           /* minimum number of quadrants per processor */
1024*0a96aa3bSJed Brown                                                              initLevel,   /* level of refinement */
1025*0a96aa3bSJed Brown                                                              1,           /* uniform refinement */
1026*0a96aa3bSJed Brown                                                              0,           /* we don't allocate any per quadrant data */
1027*0a96aa3bSJed Brown                                                              NULL,        /* there is no special quadrant initialization */
1028*0a96aa3bSJed Brown                                                              (void*)dm)); /* this dm is the user context */
1029*0a96aa3bSJed Brown 
1030*0a96aa3bSJed Brown     if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
1031*0a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
1032*0a96aa3bSJed Brown       PetscBool  flgPattern, flgFractal;
1033*0a96aa3bSJed Brown       PetscInt   corner = 0;
1034*0a96aa3bSJed Brown       PetscInt   corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN;
1035*0a96aa3bSJed Brown       PetscReal  likelihood = 1./ P4EST_DIM;
1036*0a96aa3bSJed Brown       PetscInt   pattern;
1037*0a96aa3bSJed Brown       const char *prefix;
1038*0a96aa3bSJed Brown 
1039*0a96aa3bSJed Brown       ierr = PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix);CHKERRQ(ierr);
1040*0a96aa3bSJed Brown       ierr = PetscOptionsGetEList(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_pattern",DMRefinePatternName,PATTERN_COUNT,&pattern,&flgPattern);CHKERRQ(ierr);
1041*0a96aa3bSJed Brown       ierr = PetscOptionsGetInt(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_corner",&corner,NULL);CHKERRQ(ierr);
1042*0a96aa3bSJed Brown       ierr = PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_fractal_corners",corners,&ncorner,&flgFractal);CHKERRQ(ierr);
1043*0a96aa3bSJed Brown       ierr = PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_hash_likelihood",&likelihood,NULL);CHKERRQ(ierr);
1044*0a96aa3bSJed Brown 
1045*0a96aa3bSJed Brown       if (flgPattern) {
1046*0a96aa3bSJed Brown         DMRefinePatternCtx *ctx;
1047*0a96aa3bSJed Brown         PetscInt           maxLevel;
1048*0a96aa3bSJed Brown 
1049*0a96aa3bSJed Brown         ierr          = DMForestGetMaximumRefinement(dm,&maxLevel);CHKERRQ(ierr);
1050*0a96aa3bSJed Brown         ierr          = PetscNewLog(dm,&ctx);CHKERRQ(ierr);
1051*0a96aa3bSJed Brown         ctx->maxLevel = PetscMin(maxLevel,P4EST_QMAXLEVEL);
1052*0a96aa3bSJed Brown         if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE;
1053*0a96aa3bSJed Brown         switch (pattern) {
1054*0a96aa3bSJed Brown         case PATTERN_HASH:
1055*0a96aa3bSJed Brown           ctx->refine_fn      = DMRefinePattern_Hash;
1056*0a96aa3bSJed Brown           ctx->hashLikelihood = likelihood;
1057*0a96aa3bSJed Brown           break;
1058*0a96aa3bSJed Brown         case PATTERN_CORNER:
1059*0a96aa3bSJed Brown           ctx->corner    = corner;
1060*0a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Corner;
1061*0a96aa3bSJed Brown           break;
1062*0a96aa3bSJed Brown         case PATTERN_CENTER:
1063*0a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Center;
1064*0a96aa3bSJed Brown           break;
1065*0a96aa3bSJed Brown         case PATTERN_FRACTAL:
1066*0a96aa3bSJed Brown           if (flgFractal) {
1067*0a96aa3bSJed Brown             PetscInt i;
1068*0a96aa3bSJed Brown 
1069*0a96aa3bSJed Brown             for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE;
1070*0a96aa3bSJed Brown           } else {
1071*0a96aa3bSJed Brown #if !defined(P4_TO_P8)
1072*0a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE;
1073*0a96aa3bSJed Brown #else
1074*0a96aa3bSJed Brown             ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE;
1075*0a96aa3bSJed Brown #endif
1076*0a96aa3bSJed Brown           }
1077*0a96aa3bSJed Brown           ctx->refine_fn = DMRefinePattern_Fractal;
1078*0a96aa3bSJed Brown           break;
1079*0a96aa3bSJed Brown         default:
1080*0a96aa3bSJed Brown           SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Not a valid refinement pattern");
1081*0a96aa3bSJed Brown         }
1082*0a96aa3bSJed Brown 
1083*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) ctx;
1084*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_refine,(pforest->forest,1,ctx->refine_fn,NULL));
1085*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL));
1086*0a96aa3bSJed Brown         ierr                          = PetscFree(ctx);CHKERRQ(ierr);
1087*0a96aa3bSJed Brown         pforest->forest->user_pointer = (void*) dm;
1088*0a96aa3bSJed Brown       }
1089*0a96aa3bSJed Brown     }
1090*0a96aa3bSJed Brown   }
1091*0a96aa3bSJed Brown   if (pforest->coarsen_hierarchy) {
1092*0a96aa3bSJed Brown     PetscInt initLevel, currLevel, minLevel;
1093*0a96aa3bSJed Brown 
1094*0a96aa3bSJed Brown     ierr = DMPforestGetRefinementLevel(dm,&currLevel);CHKERRQ(ierr);
1095*0a96aa3bSJed Brown     ierr = DMForestGetInitialRefinement(dm,&initLevel);CHKERRQ(ierr);
1096*0a96aa3bSJed Brown     ierr = DMForestGetMinimumRefinement(dm,&minLevel);CHKERRQ(ierr);
1097*0a96aa3bSJed Brown     if (currLevel > minLevel) {
1098*0a96aa3bSJed Brown       DM_Forest_pforest *coarse_pforest;
1099*0a96aa3bSJed Brown       DMLabel           coarsen;
1100*0a96aa3bSJed Brown       DM                coarseDM;
1101*0a96aa3bSJed Brown 
1102*0a96aa3bSJed Brown       ierr = DMForestTemplate(dm,MPI_COMM_NULL,&coarseDM);CHKERRQ(ierr);
1103*0a96aa3bSJed Brown       ierr = DMForestSetAdaptivityPurpose(coarseDM,DM_ADAPT_COARSEN);CHKERRQ(ierr);
1104*0a96aa3bSJed Brown       ierr = DMLabelCreate(PETSC_COMM_SELF, "coarsen",&coarsen);CHKERRQ(ierr);
1105*0a96aa3bSJed Brown       ierr = DMLabelSetDefaultValue(coarsen,DM_ADAPT_COARSEN);CHKERRQ(ierr);
1106*0a96aa3bSJed Brown       ierr = DMForestSetAdaptivityLabel(coarseDM,coarsen);CHKERRQ(ierr);
1107*0a96aa3bSJed Brown       ierr = DMLabelDestroy(&coarsen);CHKERRQ(ierr);
1108*0a96aa3bSJed Brown       ierr = DMSetCoarseDM(dm,coarseDM);CHKERRQ(ierr);
1109*0a96aa3bSJed Brown       ierr = PetscObjectDereference((PetscObject)coarseDM);CHKERRQ(ierr);
1110*0a96aa3bSJed Brown       initLevel = currLevel == initLevel ? initLevel - 1 : initLevel;
1111*0a96aa3bSJed Brown       ierr                              = DMForestSetInitialRefinement(coarseDM,initLevel);CHKERRQ(ierr);
1112*0a96aa3bSJed Brown       ierr                              = DMForestSetMinimumRefinement(coarseDM,minLevel);CHKERRQ(ierr);
1113*0a96aa3bSJed Brown       coarse_pforest                    = (DM_Forest_pforest*) ((DM_Forest*) coarseDM->data)->data;
1114*0a96aa3bSJed Brown       coarse_pforest->coarsen_hierarchy = PETSC_TRUE;
1115*0a96aa3bSJed Brown     }
1116*0a96aa3bSJed Brown   }
1117*0a96aa3bSJed Brown 
1118*0a96aa3bSJed Brown   { /* repartitioning and overlap */
1119*0a96aa3bSJed Brown     PetscMPIInt size, rank;
1120*0a96aa3bSJed Brown 
1121*0a96aa3bSJed Brown     ierr = MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size);CHKERRMPI(ierr);
1122*0a96aa3bSJed Brown     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRMPI(ierr);
1123*0a96aa3bSJed Brown     if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) {
1124*0a96aa3bSJed Brown       PetscBool      copyForest   = PETSC_FALSE;
1125*0a96aa3bSJed Brown       p4est_t        *forest_copy = NULL;
1126*0a96aa3bSJed Brown       p4est_gloidx_t shipped      = 0;
1127*0a96aa3bSJed Brown 
1128*0a96aa3bSJed Brown       if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE;
1129*0a96aa3bSJed Brown       if (copyForest) PetscStackCallP4estReturn(forest_copy,p4est_copy,(pforest->forest,0));
1130*0a96aa3bSJed Brown 
1131*0a96aa3bSJed Brown       if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) {
1132*0a96aa3bSJed Brown         PetscStackCallP4estReturn(shipped,p4est_partition_ext,(pforest->forest,(int)pforest->partition_for_coarsening,NULL));
1133*0a96aa3bSJed Brown       } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Non-uniform partition cases not implemented yet");
1134*0a96aa3bSJed Brown       if (shipped) ctx.anyChange = PETSC_TRUE;
1135*0a96aa3bSJed Brown       if (forest_copy) {
1136*0a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
1137*0a96aa3bSJed Brown           PetscSF        repartSF; /* repartSF has roots in the old partition */
1138*0a96aa3bSJed Brown           PetscInt       pStart = -1, pEnd = -1, p;
1139*0a96aa3bSJed Brown           PetscInt       numRoots, numLeaves;
1140*0a96aa3bSJed Brown           PetscSFNode    *repartRoots;
1141*0a96aa3bSJed Brown           p4est_gloidx_t postStart  = pforest->forest->global_first_quadrant[rank];
1142*0a96aa3bSJed Brown           p4est_gloidx_t postEnd    = pforest->forest->global_first_quadrant[rank+1];
1143*0a96aa3bSJed Brown           p4est_gloidx_t partOffset = postStart;
1144*0a96aa3bSJed Brown 
1145*0a96aa3bSJed Brown           numRoots  = (PetscInt) (forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]);
1146*0a96aa3bSJed Brown           numLeaves = (PetscInt) (postEnd - postStart);
1147*0a96aa3bSJed Brown           ierr      = DMPforestComputeOverlappingRanks(size,rank,pforest->forest,forest_copy,&pStart,&pEnd);CHKERRQ(ierr);
1148*0a96aa3bSJed Brown           ierr      = PetscMalloc1((PetscInt) pforest->forest->local_num_quadrants,&repartRoots);CHKERRQ(ierr);
1149*0a96aa3bSJed Brown           for (p = pStart; p < pEnd; p++) {
1150*0a96aa3bSJed Brown             p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p];
1151*0a96aa3bSJed Brown             p4est_gloidx_t preEnd   = forest_copy->global_first_quadrant[p+1];
1152*0a96aa3bSJed Brown             PetscInt       q;
1153*0a96aa3bSJed Brown 
1154*0a96aa3bSJed Brown             if (preEnd == preStart) continue;
1155*0a96aa3bSJed Brown             if (preStart > postStart) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Bad partition overlap computation");
1156*0a96aa3bSJed Brown             preEnd = preEnd > postEnd ? postEnd : preEnd;
1157*0a96aa3bSJed Brown             for (q = partOffset; q < preEnd; q++) {
1158*0a96aa3bSJed Brown               repartRoots[q - postStart].rank  = p;
1159*0a96aa3bSJed Brown               repartRoots[q - postStart].index = partOffset - preStart;
1160*0a96aa3bSJed Brown             }
1161*0a96aa3bSJed Brown             partOffset = preEnd;
1162*0a96aa3bSJed Brown           }
1163*0a96aa3bSJed Brown           ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm),&repartSF);CHKERRQ(ierr);
1164*0a96aa3bSJed Brown           ierr = PetscSFSetGraph(repartSF,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,repartRoots,PETSC_OWN_POINTER);CHKERRQ(ierr);
1165*0a96aa3bSJed Brown           ierr = PetscSFSetUp(repartSF);CHKERRQ(ierr);
1166*0a96aa3bSJed Brown           if (preCoarseToFine) {
1167*0a96aa3bSJed Brown             PetscSF        repartSFembed, preCoarseToFineNew;
1168*0a96aa3bSJed Brown             PetscInt       nleaves;
1169*0a96aa3bSJed Brown             const PetscInt *leaves;
1170*0a96aa3bSJed Brown 
1171*0a96aa3bSJed Brown             ierr = PetscSFSetUp(preCoarseToFine);CHKERRQ(ierr);
1172*0a96aa3bSJed Brown             ierr = PetscSFGetGraph(preCoarseToFine,NULL,&nleaves,&leaves,NULL);CHKERRQ(ierr);
1173*0a96aa3bSJed Brown             if (leaves) {
1174*0a96aa3bSJed Brown               ierr = PetscSFCreateEmbeddedRootSF(repartSF,nleaves,leaves,&repartSFembed);CHKERRQ(ierr);
1175*0a96aa3bSJed Brown             } else {
1176*0a96aa3bSJed Brown               repartSFembed = repartSF;
1177*0a96aa3bSJed Brown               ierr          = PetscObjectReference((PetscObject)repartSFembed);CHKERRQ(ierr);
1178*0a96aa3bSJed Brown             }
1179*0a96aa3bSJed Brown             ierr            = PetscSFCompose(preCoarseToFine,repartSFembed,&preCoarseToFineNew);CHKERRQ(ierr);
1180*0a96aa3bSJed Brown             ierr            = PetscSFDestroy(&preCoarseToFine);CHKERRQ(ierr);
1181*0a96aa3bSJed Brown             ierr            = PetscSFDestroy(&repartSFembed);CHKERRQ(ierr);
1182*0a96aa3bSJed Brown             preCoarseToFine = preCoarseToFineNew;
1183*0a96aa3bSJed Brown           }
1184*0a96aa3bSJed Brown           if (coarseToPreFine) {
1185*0a96aa3bSJed Brown             PetscSF repartSFinv, coarseToPreFineNew;
1186*0a96aa3bSJed Brown 
1187*0a96aa3bSJed Brown             ierr            = PetscSFCreateInverseSF(repartSF,&repartSFinv);CHKERRQ(ierr);
1188*0a96aa3bSJed Brown             ierr            = PetscSFCompose(repartSFinv,coarseToPreFine,&coarseToPreFineNew);CHKERRQ(ierr);
1189*0a96aa3bSJed Brown             ierr            = PetscSFDestroy(&coarseToPreFine);CHKERRQ(ierr);
1190*0a96aa3bSJed Brown             ierr            = PetscSFDestroy(&repartSFinv);CHKERRQ(ierr);
1191*0a96aa3bSJed Brown             coarseToPreFine = coarseToPreFineNew;
1192*0a96aa3bSJed Brown           }
1193*0a96aa3bSJed Brown           ierr = PetscSFDestroy(&repartSF);CHKERRQ(ierr);
1194*0a96aa3bSJed Brown         }
1195*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_destroy,(forest_copy));
1196*0a96aa3bSJed Brown       }
1197*0a96aa3bSJed Brown     }
1198*0a96aa3bSJed Brown     if (size > 1) {
1199*0a96aa3bSJed Brown       PetscInt overlap;
1200*0a96aa3bSJed Brown 
1201*0a96aa3bSJed Brown       ierr = DMForestGetPartitionOverlap(dm,&overlap);CHKERRQ(ierr);
1202*0a96aa3bSJed Brown 
1203*0a96aa3bSJed Brown       if (adaptFrom) {
1204*0a96aa3bSJed Brown         PetscInt aoverlap;
1205*0a96aa3bSJed Brown 
1206*0a96aa3bSJed Brown         ierr = DMForestGetPartitionOverlap(adaptFrom,&aoverlap);CHKERRQ(ierr);
1207*0a96aa3bSJed Brown         if (aoverlap != overlap) {
1208*0a96aa3bSJed Brown           ctx.anyChange = PETSC_TRUE;
1209*0a96aa3bSJed Brown         }
1210*0a96aa3bSJed Brown       }
1211*0a96aa3bSJed Brown 
1212*0a96aa3bSJed Brown       if (overlap > 0) {
1213*0a96aa3bSJed Brown         PetscInt i, cLocalStart;
1214*0a96aa3bSJed Brown         PetscInt cEnd;
1215*0a96aa3bSJed Brown         PetscSF  preCellSF = NULL, cellSF = NULL;
1216*0a96aa3bSJed Brown 
1217*0a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->ghost,p4est_ghost_new,(pforest->forest,P4EST_CONNECT_FULL));
1218*0a96aa3bSJed Brown         PetscStackCallP4estReturn(pforest->lnodes,p4est_lnodes_new,(pforest->forest,pforest->ghost,-P4EST_DIM));
1219*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_ghost_support_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
1220*0a96aa3bSJed Brown         for (i = 1; i < overlap; i++) PetscStackCallP4est(p4est_ghost_expand_by_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost));
1221*0a96aa3bSJed Brown 
1222*0a96aa3bSJed Brown         cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank];
1223*0a96aa3bSJed Brown         cEnd        = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size];
1224*0a96aa3bSJed Brown 
1225*0a96aa3bSJed Brown         /* shift sfs by cLocalStart, expand by cell SFs */
1226*0a96aa3bSJed Brown         if (preCoarseToFine || coarseToPreFine) {
1227*0a96aa3bSJed Brown           if (adaptFrom) {ierr = DMForestGetCellSF(adaptFrom,&preCellSF);CHKERRQ(ierr);}
1228*0a96aa3bSJed Brown           dm->setupcalled = PETSC_TRUE;
1229*0a96aa3bSJed Brown           ierr = DMForestGetCellSF(dm,&cellSF);CHKERRQ(ierr);
1230*0a96aa3bSJed Brown         }
1231*0a96aa3bSJed Brown         if (preCoarseToFine) {
1232*0a96aa3bSJed Brown           PetscSF           preCoarseToFineNew;
1233*0a96aa3bSJed Brown           PetscInt          nleaves, nroots, *leavesNew, i, nleavesNew;
1234*0a96aa3bSJed Brown           const PetscInt    *leaves;
1235*0a96aa3bSJed Brown           const PetscSFNode *remotes;
1236*0a96aa3bSJed Brown           PetscSFNode       *remotesAll;
1237*0a96aa3bSJed Brown 
1238*0a96aa3bSJed Brown           ierr = PetscSFSetUp(preCoarseToFine);CHKERRQ(ierr);
1239*0a96aa3bSJed Brown           ierr = PetscSFGetGraph(preCoarseToFine,&nroots,&nleaves,&leaves,&remotes);CHKERRQ(ierr);
1240*0a96aa3bSJed Brown           ierr = PetscMalloc1(cEnd,&remotesAll);CHKERRQ(ierr);
1241*0a96aa3bSJed Brown           for (i = 0; i < cEnd; i++) {
1242*0a96aa3bSJed Brown             remotesAll[i].rank  = -1;
1243*0a96aa3bSJed Brown             remotesAll[i].index = -1;
1244*0a96aa3bSJed Brown           }
1245*0a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i];
1246*0a96aa3bSJed Brown           ierr       = PetscSFSetUp(cellSF);CHKERRQ(ierr);
1247*0a96aa3bSJed Brown           ierr       = PetscSFBcastBegin(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE);CHKERRQ(ierr);
1248*0a96aa3bSJed Brown           ierr       = PetscSFBcastEnd(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE);CHKERRQ(ierr);
1249*0a96aa3bSJed Brown           nleavesNew = 0;
1250*0a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
1251*0a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) nleavesNew++;
1252*0a96aa3bSJed Brown           }
1253*0a96aa3bSJed Brown           ierr       = PetscMalloc1(nleavesNew,&leavesNew);CHKERRQ(ierr);
1254*0a96aa3bSJed Brown           nleavesNew = 0;
1255*0a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) {
1256*0a96aa3bSJed Brown             if (remotesAll[i].rank >= 0) {
1257*0a96aa3bSJed Brown               leavesNew[nleavesNew] = i;
1258*0a96aa3bSJed Brown               if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i];
1259*0a96aa3bSJed Brown               nleavesNew++;
1260*0a96aa3bSJed Brown             }
1261*0a96aa3bSJed Brown           }
1262*0a96aa3bSJed Brown           ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm),&preCoarseToFineNew);CHKERRQ(ierr);
1263*0a96aa3bSJed Brown           if (nleavesNew < cEnd) {
1264*0a96aa3bSJed Brown             ierr = PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,leavesNew,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES);CHKERRQ(ierr);
1265*0a96aa3bSJed Brown           } else { /* all cells are leaves */
1266*0a96aa3bSJed Brown             ierr = PetscFree(leavesNew);CHKERRQ(ierr);
1267*0a96aa3bSJed Brown             ierr = PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,NULL,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES);CHKERRQ(ierr);
1268*0a96aa3bSJed Brown           }
1269*0a96aa3bSJed Brown           ierr            = PetscFree(remotesAll);CHKERRQ(ierr);
1270*0a96aa3bSJed Brown           ierr            = PetscSFDestroy(&preCoarseToFine);CHKERRQ(ierr);
1271*0a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
1272*0a96aa3bSJed Brown           preCoarseToFine = preCoarseToFineNew;
1273*0a96aa3bSJed Brown         }
1274*0a96aa3bSJed Brown         if (coarseToPreFine) {
1275*0a96aa3bSJed Brown           PetscSF           coarseToPreFineNew;
1276*0a96aa3bSJed Brown           PetscInt          nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew;
1277*0a96aa3bSJed Brown           const PetscInt    *leaves;
1278*0a96aa3bSJed Brown           const PetscSFNode *remotes;
1279*0a96aa3bSJed Brown           PetscSFNode       *remotesNew, *remotesNewRoot, *remotesExpanded;
1280*0a96aa3bSJed Brown 
1281*0a96aa3bSJed Brown           ierr = PetscSFSetUp(coarseToPreFine);CHKERRQ(ierr);
1282*0a96aa3bSJed Brown           ierr = PetscSFGetGraph(coarseToPreFine,&nroots,&nleaves,&leaves,&remotes);CHKERRQ(ierr);
1283*0a96aa3bSJed Brown           ierr = PetscSFGetGraph(preCellSF,NULL,&nleavesCellSF,NULL,NULL);CHKERRQ(ierr);
1284*0a96aa3bSJed Brown           ierr = PetscMalloc1(nroots,&remotesNewRoot);CHKERRQ(ierr);
1285*0a96aa3bSJed Brown           ierr = PetscMalloc1(nleaves,&remotesNew);CHKERRQ(ierr);
1286*0a96aa3bSJed Brown           for (i = 0; i < nroots; i++) {
1287*0a96aa3bSJed Brown             remotesNewRoot[i].rank  = rank;
1288*0a96aa3bSJed Brown             remotesNewRoot[i].index = i + cLocalStart;
1289*0a96aa3bSJed Brown           }
1290*0a96aa3bSJed Brown           ierr = PetscSFBcastBegin(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE);CHKERRQ(ierr);
1291*0a96aa3bSJed Brown           ierr = PetscSFBcastEnd(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE);CHKERRQ(ierr);
1292*0a96aa3bSJed Brown           ierr = PetscFree(remotesNewRoot);CHKERRQ(ierr);
1293*0a96aa3bSJed Brown           ierr = PetscMalloc1(nleavesCellSF,&remotesExpanded);CHKERRQ(ierr);
1294*0a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
1295*0a96aa3bSJed Brown             remotesExpanded[i].rank  = -1;
1296*0a96aa3bSJed Brown             remotesExpanded[i].index = -1;
1297*0a96aa3bSJed Brown           }
1298*0a96aa3bSJed Brown           for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i];
1299*0a96aa3bSJed Brown           ierr = PetscFree(remotesNew);CHKERRQ(ierr);
1300*0a96aa3bSJed Brown           ierr = PetscSFBcastBegin(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE);CHKERRQ(ierr);
1301*0a96aa3bSJed Brown           ierr = PetscSFBcastEnd(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE);CHKERRQ(ierr);
1302*0a96aa3bSJed Brown 
1303*0a96aa3bSJed Brown           nleavesExpanded = 0;
1304*0a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
1305*0a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) nleavesExpanded++;
1306*0a96aa3bSJed Brown           }
1307*0a96aa3bSJed Brown           ierr            = PetscMalloc1(nleavesExpanded,&leavesNew);CHKERRQ(ierr);
1308*0a96aa3bSJed Brown           nleavesExpanded = 0;
1309*0a96aa3bSJed Brown           for (i = 0; i < nleavesCellSF; i++) {
1310*0a96aa3bSJed Brown             if (remotesExpanded[i].rank >= 0) {
1311*0a96aa3bSJed Brown               leavesNew[nleavesExpanded] = i;
1312*0a96aa3bSJed Brown               if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i];
1313*0a96aa3bSJed Brown               nleavesExpanded++;
1314*0a96aa3bSJed Brown             }
1315*0a96aa3bSJed Brown           }
1316*0a96aa3bSJed Brown           ierr = PetscSFCreate(PetscObjectComm((PetscObject)dm),&coarseToPreFineNew);CHKERRQ(ierr);
1317*0a96aa3bSJed Brown           if (nleavesExpanded < nleavesCellSF) {
1318*0a96aa3bSJed Brown             ierr = PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,leavesNew,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES);CHKERRQ(ierr);
1319*0a96aa3bSJed Brown           } else {
1320*0a96aa3bSJed Brown             ierr = PetscFree(leavesNew);CHKERRQ(ierr);
1321*0a96aa3bSJed Brown             ierr = PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,NULL,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES);CHKERRQ(ierr);
1322*0a96aa3bSJed Brown           }
1323*0a96aa3bSJed Brown           ierr            = PetscFree(remotesExpanded);CHKERRQ(ierr);
1324*0a96aa3bSJed Brown           ierr            = PetscSFDestroy(&coarseToPreFine);CHKERRQ(ierr);
1325*0a96aa3bSJed Brown           coarseToPreFine = coarseToPreFineNew;
1326*0a96aa3bSJed Brown         }
1327*0a96aa3bSJed Brown       }
1328*0a96aa3bSJed Brown     }
1329*0a96aa3bSJed Brown   }
1330*0a96aa3bSJed Brown   forest->preCoarseToFine = preCoarseToFine;
1331*0a96aa3bSJed Brown   forest->coarseToPreFine = coarseToPreFine;
1332*0a96aa3bSJed Brown   dm->setupcalled         = PETSC_TRUE;
1333*0a96aa3bSJed Brown   ierr = MPI_Allreduce(&ctx.anyChange,&(pforest->adaptivitySuccess),1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
1334*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,NULL);CHKERRQ(ierr);
1335*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1336*0a96aa3bSJed Brown }
1337*0a96aa3bSJed Brown 
1338*0a96aa3bSJed Brown #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess)
1339*0a96aa3bSJed Brown static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success)
1340*0a96aa3bSJed Brown {
1341*0a96aa3bSJed Brown   DM_Forest         *forest;
1342*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
1343*0a96aa3bSJed Brown 
1344*0a96aa3bSJed Brown   PetscFunctionBegin;
1345*0a96aa3bSJed Brown   forest   = (DM_Forest *) dm->data;
1346*0a96aa3bSJed Brown   pforest  = (DM_Forest_pforest *) forest->data;
1347*0a96aa3bSJed Brown   *success = pforest->adaptivitySuccess;
1348*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1349*0a96aa3bSJed Brown }
1350*0a96aa3bSJed Brown 
1351*0a96aa3bSJed Brown #define DMView_ASCII_pforest _append_pforest(DMView_ASCII)
1352*0a96aa3bSJed Brown static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer)
1353*0a96aa3bSJed Brown {
1354*0a96aa3bSJed Brown   DM             dm = (DM) odm;
1355*0a96aa3bSJed Brown   PetscErrorCode ierr;
1356*0a96aa3bSJed Brown 
1357*0a96aa3bSJed Brown   PetscFunctionBegin;
1358*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1359*0a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1360*0a96aa3bSJed Brown   ierr = DMSetUp(dm);CHKERRQ(ierr);
1361*0a96aa3bSJed Brown   switch (viewer->format) {
1362*0a96aa3bSJed Brown   case PETSC_VIEWER_DEFAULT:
1363*0a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO:
1364*0a96aa3bSJed Brown   {
1365*0a96aa3bSJed Brown     PetscInt   dim;
1366*0a96aa3bSJed Brown     const char *name;
1367*0a96aa3bSJed Brown 
1368*0a96aa3bSJed Brown     ierr = PetscObjectGetName((PetscObject) dm, &name);CHKERRQ(ierr);
1369*0a96aa3bSJed Brown     ierr = DMGetDimension(dm, &dim);CHKERRQ(ierr);
1370*0a96aa3bSJed Brown     if (name) {ierr = PetscViewerASCIIPrintf(viewer, "Forest %s in %D dimensions:\n", name, dim);CHKERRQ(ierr);}
1371*0a96aa3bSJed Brown     else      {ierr = PetscViewerASCIIPrintf(viewer, "Forest in %D dimensions:\n", dim);CHKERRQ(ierr);}
1372*0a96aa3bSJed Brown   }
1373*0a96aa3bSJed Brown   case PETSC_VIEWER_ASCII_INFO_DETAIL:
1374*0a96aa3bSJed Brown   case PETSC_VIEWER_LOAD_BALANCE:
1375*0a96aa3bSJed Brown   {
1376*0a96aa3bSJed Brown     DM plex;
1377*0a96aa3bSJed Brown 
1378*0a96aa3bSJed Brown     ierr = DMPforestGetPlex(dm, &plex);CHKERRQ(ierr);
1379*0a96aa3bSJed Brown     ierr = DMView(plex, viewer);CHKERRQ(ierr);
1380*0a96aa3bSJed Brown   }
1381*0a96aa3bSJed Brown   break;
1382*0a96aa3bSJed Brown   default: SETERRQ1(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
1383*0a96aa3bSJed Brown   }
1384*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1385*0a96aa3bSJed Brown }
1386*0a96aa3bSJed Brown 
1387*0a96aa3bSJed Brown #define DMView_VTK_pforest _append_pforest(DMView_VTK)
1388*0a96aa3bSJed Brown static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer)
1389*0a96aa3bSJed Brown {
1390*0a96aa3bSJed Brown   DM                dm       = (DM) odm;
1391*0a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
1392*0a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
1393*0a96aa3bSJed Brown   PetscBool         isvtk;
1394*0a96aa3bSJed Brown   PetscReal         vtkScale = 1. - PETSC_MACHINE_EPSILON;
1395*0a96aa3bSJed Brown   PetscViewer_VTK   *vtk     = (PetscViewer_VTK*)viewer->data;
1396*0a96aa3bSJed Brown   const char        *name;
1397*0a96aa3bSJed Brown   char              *filenameStrip = NULL;
1398*0a96aa3bSJed Brown   PetscBool         hasExt;
1399*0a96aa3bSJed Brown   size_t            len;
1400*0a96aa3bSJed Brown   p4est_geometry_t  *geom;
1401*0a96aa3bSJed Brown   PetscErrorCode    ierr;
1402*0a96aa3bSJed Brown 
1403*0a96aa3bSJed Brown   PetscFunctionBegin;
1404*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1405*0a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1406*0a96aa3bSJed Brown   ierr = DMSetUp(dm);CHKERRQ(ierr);
1407*0a96aa3bSJed Brown   geom = pforest->topo->geom;
1408*0a96aa3bSJed Brown   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk);CHKERRQ(ierr);
1409*0a96aa3bSJed Brown   if (!isvtk) SETERRQ1(PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name);
1410*0a96aa3bSJed Brown   switch (viewer->format) {
1411*0a96aa3bSJed Brown   case PETSC_VIEWER_VTK_VTU:
1412*0a96aa3bSJed Brown     if (!pforest->forest) SETERRQ (PetscObjectComm(odm),PETSC_ERR_ARG_WRONG,"DM has not been setup with a valid forest");
1413*0a96aa3bSJed Brown     name = vtk->filename;
1414*0a96aa3bSJed Brown     ierr = PetscStrlen(name,&len);CHKERRQ(ierr);
1415*0a96aa3bSJed Brown     ierr = PetscStrcasecmp(name+len-4,".vtu",&hasExt);CHKERRQ(ierr);
1416*0a96aa3bSJed Brown     if (hasExt) {
1417*0a96aa3bSJed Brown       ierr                = PetscStrallocpy(name,&filenameStrip);CHKERRQ(ierr);
1418*0a96aa3bSJed Brown       filenameStrip[len-4]='\0';
1419*0a96aa3bSJed Brown       name                = filenameStrip;
1420*0a96aa3bSJed Brown     }
1421*0a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4estReturn(geom,p4est_geometry_new_connectivity,(pforest->topo->conn));
1422*0a96aa3bSJed Brown     {
1423*0a96aa3bSJed Brown       p4est_vtk_context_t *pvtk;
1424*0a96aa3bSJed Brown       int                 footerr;
1425*0a96aa3bSJed Brown 
1426*0a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_context_new,(pforest->forest,name));
1427*0a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_geom,(pvtk,geom));
1428*0a96aa3bSJed Brown       PetscStackCallP4est(p4est_vtk_context_set_scale,(pvtk,(double)vtkScale));
1429*0a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_header,(pvtk));
1430*0a96aa3bSJed Brown       if (!pvtk) SETERRQ(PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_header() failed");
1431*0a96aa3bSJed Brown       PetscStackCallP4estReturn(pvtk,p4est_vtk_write_cell_dataf,(pvtk,
1432*0a96aa3bSJed Brown                                                                  1, /* write tree */
1433*0a96aa3bSJed Brown                                                                  1, /* write level */
1434*0a96aa3bSJed Brown                                                                  1, /* write rank */
1435*0a96aa3bSJed Brown                                                                  0, /* do not wrap rank */
1436*0a96aa3bSJed Brown                                                                  0, /* no scalar fields */
1437*0a96aa3bSJed Brown                                                                  0, /* no vector fields */
1438*0a96aa3bSJed Brown                                                                  pvtk));
1439*0a96aa3bSJed Brown       if (!pvtk) SETERRQ(PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_cell_dataf() failed");
1440*0a96aa3bSJed Brown       PetscStackCallP4estReturn(footerr,p4est_vtk_write_footer,(pvtk));
1441*0a96aa3bSJed Brown       if (footerr) SETERRQ(PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_footer() failed");
1442*0a96aa3bSJed Brown     }
1443*0a96aa3bSJed Brown     if (!pforest->topo->geom) PetscStackCallP4est(p4est_geometry_destroy,(geom));
1444*0a96aa3bSJed Brown     ierr = PetscFree(filenameStrip);CHKERRQ(ierr);
1445*0a96aa3bSJed Brown     break;
1446*0a96aa3bSJed Brown   default: SETERRQ1(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]);
1447*0a96aa3bSJed Brown   }
1448*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1449*0a96aa3bSJed Brown }
1450*0a96aa3bSJed Brown 
1451*0a96aa3bSJed Brown #define DMView_HDF5_pforest _append_pforest(DMView_HDF5)
1452*0a96aa3bSJed Brown static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer)
1453*0a96aa3bSJed Brown {
1454*0a96aa3bSJed Brown   DM             plex;
1455*0a96aa3bSJed Brown   PetscErrorCode ierr;
1456*0a96aa3bSJed Brown 
1457*0a96aa3bSJed Brown   PetscFunctionBegin;
1458*0a96aa3bSJed Brown   ierr = DMSetUp(dm);CHKERRQ(ierr);
1459*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm, &plex);CHKERRQ(ierr);
1460*0a96aa3bSJed Brown   ierr = DMView(plex, viewer);CHKERRQ(ierr);
1461*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1462*0a96aa3bSJed Brown }
1463*0a96aa3bSJed Brown 
1464*0a96aa3bSJed Brown #define DMView_GLVis_pforest _append_pforest(DMView_GLVis)
1465*0a96aa3bSJed Brown static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer)
1466*0a96aa3bSJed Brown {
1467*0a96aa3bSJed Brown   DM             plex;
1468*0a96aa3bSJed Brown   PetscErrorCode ierr;
1469*0a96aa3bSJed Brown 
1470*0a96aa3bSJed Brown   PetscFunctionBegin;
1471*0a96aa3bSJed Brown   ierr = DMSetUp(dm);CHKERRQ(ierr);
1472*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm, &plex);CHKERRQ(ierr);
1473*0a96aa3bSJed Brown   ierr = DMView(plex, viewer);CHKERRQ(ierr);
1474*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1475*0a96aa3bSJed Brown }
1476*0a96aa3bSJed Brown 
1477*0a96aa3bSJed Brown #define DMView_pforest _append_pforest(DMView)
1478*0a96aa3bSJed Brown static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer)
1479*0a96aa3bSJed Brown {
1480*0a96aa3bSJed Brown   PetscBool      isascii, isvtk, ishdf5, isglvis;
1481*0a96aa3bSJed Brown   PetscErrorCode ierr;
1482*0a96aa3bSJed Brown 
1483*0a96aa3bSJed Brown   PetscFunctionBegin;
1484*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm, DM_CLASSID, 1);
1485*0a96aa3bSJed Brown   PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2);
1486*0a96aa3bSJed Brown   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii);CHKERRQ(ierr);
1487*0a96aa3bSJed Brown   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK,   &isvtk);CHKERRQ(ierr);
1488*0a96aa3bSJed Brown   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5,  &ishdf5);CHKERRQ(ierr);
1489*0a96aa3bSJed Brown   ierr = PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis);CHKERRQ(ierr);
1490*0a96aa3bSJed Brown   if (isascii) {
1491*0a96aa3bSJed Brown     ierr = DMView_ASCII_pforest((PetscObject) dm,viewer);CHKERRQ(ierr);
1492*0a96aa3bSJed Brown   } else if (isvtk) {
1493*0a96aa3bSJed Brown     ierr = DMView_VTK_pforest((PetscObject) dm,viewer);CHKERRQ(ierr);
1494*0a96aa3bSJed Brown   } else if (ishdf5) {
1495*0a96aa3bSJed Brown     ierr = DMView_HDF5_pforest(dm, viewer);CHKERRQ(ierr);
1496*0a96aa3bSJed Brown   } else if (isglvis) {
1497*0a96aa3bSJed Brown     ierr = DMView_GLVis_pforest(dm, viewer);CHKERRQ(ierr);
1498*0a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject) dm),PETSC_ERR_SUP,"Viewer not supported (not VTK, HDF5, or GLVis)");
1499*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1500*0a96aa3bSJed Brown }
1501*0a96aa3bSJed Brown 
1502*0a96aa3bSJed Brown static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq)
1503*0a96aa3bSJed Brown {
1504*0a96aa3bSJed Brown   PetscInt       *ttf, f, t, g, count;
1505*0a96aa3bSJed Brown   PetscInt       numFacets;
1506*0a96aa3bSJed Brown   PetscErrorCode ierr;
1507*0a96aa3bSJed Brown 
1508*0a96aa3bSJed Brown   PetscFunctionBegin;
1509*0a96aa3bSJed Brown   numFacets = conn->num_trees * P4EST_FACES;
1510*0a96aa3bSJed Brown   ierr      = PetscMalloc1(numFacets,&ttf);CHKERRQ(ierr);
1511*0a96aa3bSJed Brown   for (f = 0; f < numFacets; f++) ttf[f] = -1;
1512*0a96aa3bSJed Brown   for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) {
1513*0a96aa3bSJed Brown     for (f = 0; f < P4EST_FACES; f++, g++) {
1514*0a96aa3bSJed Brown       if (ttf[g] == -1) {
1515*0a96aa3bSJed Brown         PetscInt ng;
1516*0a96aa3bSJed Brown 
1517*0a96aa3bSJed Brown         ttf[g]  = count++;
1518*0a96aa3bSJed Brown         ng      = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES);
1519*0a96aa3bSJed Brown         ttf[ng] = ttf[g];
1520*0a96aa3bSJed Brown       }
1521*0a96aa3bSJed Brown     }
1522*0a96aa3bSJed Brown   }
1523*0a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
1524*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1525*0a96aa3bSJed Brown }
1526*0a96aa3bSJed Brown 
1527*0a96aa3bSJed Brown static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq)
1528*0a96aa3bSJed Brown {
1529*0a96aa3bSJed Brown   p4est_topidx_t       numTrees, numVerts, numCorns, numCtt;
1530*0a96aa3bSJed Brown   PetscSection         ctt;
1531*0a96aa3bSJed Brown #if defined(P4_TO_P8)
1532*0a96aa3bSJed Brown   p4est_topidx_t       numEdges, numEtt;
1533*0a96aa3bSJed Brown   PetscSection         ett;
1534*0a96aa3bSJed Brown   PetscInt             eStart, eEnd, e, ettSize;
1535*0a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES + P8EST_EDGES;
1536*0a96aa3bSJed Brown   PetscInt             edgeOff = 1 + P4EST_FACES;
1537*0a96aa3bSJed Brown #else
1538*0a96aa3bSJed Brown   PetscInt             vertOff = 1 + P4EST_FACES;
1539*0a96aa3bSJed Brown #endif
1540*0a96aa3bSJed Brown   p4est_connectivity_t *conn;
1541*0a96aa3bSJed Brown   PetscInt             cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f;
1542*0a96aa3bSJed Brown   PetscInt             *star = NULL, *closure = NULL, closureSize, starSize, cttSize;
1543*0a96aa3bSJed Brown   PetscInt             *ttf;
1544*0a96aa3bSJed Brown   PetscErrorCode       ierr;
1545*0a96aa3bSJed Brown 
1546*0a96aa3bSJed Brown   PetscFunctionBegin;
1547*0a96aa3bSJed Brown   /* 1: count objects, allocate */
1548*0a96aa3bSJed Brown   ierr = DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd);CHKERRQ(ierr);
1549*0a96aa3bSJed Brown   ierr = P4estTopidxCast(cEnd-cStart,&numTrees);CHKERRQ(ierr);
1550*0a96aa3bSJed Brown   numVerts = P4EST_CHILDREN * numTrees;
1551*0a96aa3bSJed Brown   ierr = DMPlexGetDepthStratum(dm,0,&vStart,&vEnd);CHKERRQ(ierr);
1552*0a96aa3bSJed Brown   ierr = P4estTopidxCast(vEnd-vStart,&numCorns);CHKERRQ(ierr);
1553*0a96aa3bSJed Brown   ierr = PetscSectionCreate(PETSC_COMM_SELF,&ctt);CHKERRQ(ierr);
1554*0a96aa3bSJed Brown   ierr = PetscSectionSetChart(ctt,vStart,vEnd);CHKERRQ(ierr);
1555*0a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
1556*0a96aa3bSJed Brown     PetscInt s;
1557*0a96aa3bSJed Brown 
1558*0a96aa3bSJed Brown     ierr = DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
1559*0a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
1560*0a96aa3bSJed Brown       PetscInt p = star[2*s];
1561*0a96aa3bSJed Brown 
1562*0a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
1563*0a96aa3bSJed Brown         /* we want to count every time cell p references v, so we see how many times it comes up in the closure.  This
1564*0a96aa3bSJed Brown          * only protects against periodicity problems */
1565*0a96aa3bSJed Brown         ierr = DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1566*0a96aa3bSJed Brown         if (closureSize != P4EST_INSUL) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell %D with wrong closure size %D != %D", p, closureSize, P4EST_INSUL);
1567*0a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
1568*0a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
1569*0a96aa3bSJed Brown 
1570*0a96aa3bSJed Brown           if (cellVert < vStart || cellVert >= vEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: vertices");
1571*0a96aa3bSJed Brown           if (cellVert == v) {
1572*0a96aa3bSJed Brown             ierr = PetscSectionAddDof(ctt,v,1);CHKERRQ(ierr);
1573*0a96aa3bSJed Brown           }
1574*0a96aa3bSJed Brown         }
1575*0a96aa3bSJed Brown         ierr = DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1576*0a96aa3bSJed Brown       }
1577*0a96aa3bSJed Brown     }
1578*0a96aa3bSJed Brown     ierr = DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
1579*0a96aa3bSJed Brown   }
1580*0a96aa3bSJed Brown   ierr = PetscSectionSetUp(ctt);CHKERRQ(ierr);
1581*0a96aa3bSJed Brown   ierr = PetscSectionGetStorageSize(ctt,&cttSize);CHKERRQ(ierr);
1582*0a96aa3bSJed Brown   ierr = P4estTopidxCast(cttSize,&numCtt);CHKERRQ(ierr);
1583*0a96aa3bSJed Brown #if defined(P4_TO_P8)
1584*0a96aa3bSJed Brown   ierr = DMPlexGetSimplexOrBoxCells(dm,P4EST_DIM-1,&eStart,&eEnd);CHKERRQ(ierr);
1585*0a96aa3bSJed Brown   ierr = P4estTopidxCast(eEnd-eStart,&numEdges);CHKERRQ(ierr);
1586*0a96aa3bSJed Brown   ierr = PetscSectionCreate(PETSC_COMM_SELF,&ett);CHKERRQ(ierr);
1587*0a96aa3bSJed Brown   ierr = PetscSectionSetChart(ett,eStart,eEnd);CHKERRQ(ierr);
1588*0a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
1589*0a96aa3bSJed Brown     PetscInt s;
1590*0a96aa3bSJed Brown 
1591*0a96aa3bSJed Brown     ierr = DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
1592*0a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
1593*0a96aa3bSJed Brown       PetscInt p = star[2*s];
1594*0a96aa3bSJed Brown 
1595*0a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
1596*0a96aa3bSJed Brown         /* we want to count every time cell p references e, so we see how many times it comes up in the closure.  This
1597*0a96aa3bSJed Brown          * only protects against periodicity problems */
1598*0a96aa3bSJed Brown         ierr = DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1599*0a96aa3bSJed Brown         if (closureSize != P4EST_INSUL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell with wrong closure size");
1600*0a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
1601*0a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
1602*0a96aa3bSJed Brown 
1603*0a96aa3bSJed Brown           if (cellEdge < eStart || cellEdge >= eEnd) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: edges");
1604*0a96aa3bSJed Brown           if (cellEdge == e) {
1605*0a96aa3bSJed Brown             ierr = PetscSectionAddDof(ett,e,1);CHKERRQ(ierr);
1606*0a96aa3bSJed Brown           }
1607*0a96aa3bSJed Brown         }
1608*0a96aa3bSJed Brown         ierr = DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1609*0a96aa3bSJed Brown       }
1610*0a96aa3bSJed Brown     }
1611*0a96aa3bSJed Brown     ierr = DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
1612*0a96aa3bSJed Brown   }
1613*0a96aa3bSJed Brown   ierr = PetscSectionSetUp(ett);CHKERRQ(ierr);
1614*0a96aa3bSJed Brown   ierr = PetscSectionGetStorageSize(ett,&ettSize);CHKERRQ(ierr);
1615*0a96aa3bSJed Brown   ierr = P4estTopidxCast(ettSize,&numEtt);CHKERRQ(ierr);
1616*0a96aa3bSJed Brown 
1617*0a96aa3bSJed Brown   /* This routine allocates space for the arrays, which we fill below */
1618*0a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p8est_connectivity_new,(numVerts,numTrees,numEdges,numEtt,numCorns,numCtt));
1619*0a96aa3bSJed Brown #else
1620*0a96aa3bSJed Brown   PetscStackCallP4estReturn(conn,p4est_connectivity_new,(numVerts,numTrees,numCorns,numCtt));
1621*0a96aa3bSJed Brown #endif
1622*0a96aa3bSJed Brown 
1623*0a96aa3bSJed Brown   /* 2: visit every face, determine neighboring cells(trees) */
1624*0a96aa3bSJed Brown   ierr = DMPlexGetSimplexOrBoxCells(dm,1,&fStart,&fEnd);CHKERRQ(ierr);
1625*0a96aa3bSJed Brown   ierr = PetscMalloc1((cEnd-cStart) * P4EST_FACES,&ttf);CHKERRQ(ierr);
1626*0a96aa3bSJed Brown   for (f = fStart; f < fEnd; f++) {
1627*0a96aa3bSJed Brown     PetscInt       numSupp, s;
1628*0a96aa3bSJed Brown     PetscInt       myFace[2] = {-1, -1};
1629*0a96aa3bSJed Brown     PetscInt       myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT};
1630*0a96aa3bSJed Brown     const PetscInt *supp;
1631*0a96aa3bSJed Brown 
1632*0a96aa3bSJed Brown     ierr = DMPlexGetSupportSize(dm, f, &numSupp);CHKERRQ(ierr);
1633*0a96aa3bSJed Brown     if (numSupp != 1 && numSupp != 2) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"point %D has facet with %D sides: must be 1 or 2 (boundary or conformal)",f,numSupp);
1634*0a96aa3bSJed Brown     ierr = DMPlexGetSupport(dm, f, &supp);CHKERRQ(ierr);
1635*0a96aa3bSJed Brown 
1636*0a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
1637*0a96aa3bSJed Brown       PetscInt p = supp[s];
1638*0a96aa3bSJed Brown 
1639*0a96aa3bSJed Brown       if (p >= cEnd) {
1640*0a96aa3bSJed Brown         numSupp--;
1641*0a96aa3bSJed Brown         if (s) supp = &supp[1 - s];
1642*0a96aa3bSJed Brown         break;
1643*0a96aa3bSJed Brown       }
1644*0a96aa3bSJed Brown     }
1645*0a96aa3bSJed Brown     for (s = 0; s < numSupp; s++) {
1646*0a96aa3bSJed Brown       PetscInt       p = supp[s], i;
1647*0a96aa3bSJed Brown       PetscInt       numCone;
1648*0a96aa3bSJed Brown       DMPolytopeType ct;
1649*0a96aa3bSJed Brown       const PetscInt *cone;
1650*0a96aa3bSJed Brown       const PetscInt *ornt;
1651*0a96aa3bSJed Brown       PetscInt       orient = PETSC_MIN_INT;
1652*0a96aa3bSJed Brown 
1653*0a96aa3bSJed Brown       ierr = DMPlexGetConeSize(dm, p, &numCone);CHKERRQ(ierr);
1654*0a96aa3bSJed Brown       if (numCone != P4EST_FACES) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %D has %D facets, expect %d",p,numCone,P4EST_FACES);
1655*0a96aa3bSJed Brown       ierr = DMPlexGetCone(dm, p, &cone);CHKERRQ(ierr);
1656*0a96aa3bSJed Brown       ierr = DMPlexGetCellType(dm, cone[0], &ct);CHKERRQ(ierr);
1657*0a96aa3bSJed Brown       ierr = DMPlexGetConeOrientation(dm, p, &ornt);CHKERRQ(ierr);
1658*0a96aa3bSJed Brown       for (i = 0; i < P4EST_FACES; i++) {
1659*0a96aa3bSJed Brown         if (cone[i] == f) {
1660*0a96aa3bSJed Brown           orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]);
1661*0a96aa3bSJed Brown           break;
1662*0a96aa3bSJed Brown         }
1663*0a96aa3bSJed Brown       }
1664*0a96aa3bSJed Brown       if (i >= P4EST_FACES) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %D faced %D mismatch",p,f);
1665*0a96aa3bSJed Brown       if (p < cStart || p >= cEnd) {
1666*0a96aa3bSJed Brown         DMPolytopeType ct;
1667*0a96aa3bSJed Brown         ierr = DMPlexGetCellType(dm, p, &ct);CHKERRQ(ierr);
1668*0a96aa3bSJed Brown         SETERRQ4(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %D (%s) should be in [%D, %D)",p,DMPolytopeTypes[ct],cStart,cEnd);
1669*0a96aa3bSJed Brown       }
1670*0a96aa3bSJed Brown       ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart;
1671*0a96aa3bSJed Brown       if (numSupp == 1) {
1672*0a96aa3bSJed Brown         /* boundary faces indicated by self reference */
1673*0a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart;
1674*0a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t) PetscFaceToP4estFace[i];
1675*0a96aa3bSJed Brown       } else {
1676*0a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
1677*0a96aa3bSJed Brown 
1678*0a96aa3bSJed Brown         conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart;
1679*0a96aa3bSJed Brown         myFace[s] = PetscFaceToP4estFace[i];
1680*0a96aa3bSJed Brown         /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to
1681*0a96aa3bSJed Brown          * petsc-closure permutation and the petsc-closure to facet orientation */
1682*0a96aa3bSJed Brown         myOrnt[s] = DihedralCompose(N,orient,DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]]));
1683*0a96aa3bSJed Brown       }
1684*0a96aa3bSJed Brown     }
1685*0a96aa3bSJed Brown     if (numSupp == 2) {
1686*0a96aa3bSJed Brown       for (s = 0; s < numSupp; s++) {
1687*0a96aa3bSJed Brown         PetscInt       p = supp[s];
1688*0a96aa3bSJed Brown         PetscInt       orntAtoB;
1689*0a96aa3bSJed Brown         PetscInt       p4estOrient;
1690*0a96aa3bSJed Brown         const PetscInt N = P4EST_CHILDREN / 2;
1691*0a96aa3bSJed Brown 
1692*0a96aa3bSJed Brown         /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor
1693*0a96aa3bSJed Brown          * permutation of this cell-facet's cone */
1694*0a96aa3bSJed Brown         orntAtoB = DihedralCompose(N,DihedralInvert(N,myOrnt[1-s]),myOrnt[s]);
1695*0a96aa3bSJed Brown 
1696*0a96aa3bSJed Brown         /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e.,
1697*0a96aa3bSJed Brown          * vertices around facet) */
1698*0a96aa3bSJed Brown #if !defined(P4_TO_P8)
1699*0a96aa3bSJed Brown         p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB;
1700*0a96aa3bSJed Brown #else
1701*0a96aa3bSJed Brown         {
1702*0a96aa3bSJed Brown           PetscInt firstVert      = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB;
1703*0a96aa3bSJed Brown           PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1);
1704*0a96aa3bSJed Brown 
1705*0a96aa3bSJed Brown                                                                                            /* swap bits */
1706*0a96aa3bSJed Brown           p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1));
1707*0a96aa3bSJed Brown         }
1708*0a96aa3bSJed Brown #endif
1709*0a96aa3bSJed Brown         /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see
1710*0a96aa3bSJed Brown          * p4est_connectivity.h, p8est_connectivity.h) */
1711*0a96aa3bSJed Brown         conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t) myFace[1 - s] + p4estOrient * P4EST_FACES;
1712*0a96aa3bSJed Brown       }
1713*0a96aa3bSJed Brown     }
1714*0a96aa3bSJed Brown   }
1715*0a96aa3bSJed Brown 
1716*0a96aa3bSJed Brown #if defined(P4_TO_P8)
1717*0a96aa3bSJed Brown   /* 3: visit every edge */
1718*0a96aa3bSJed Brown   conn->ett_offset[0] = 0;
1719*0a96aa3bSJed Brown   for (e = eStart; e < eEnd; e++) {
1720*0a96aa3bSJed Brown     PetscInt off, s;
1721*0a96aa3bSJed Brown 
1722*0a96aa3bSJed Brown     ierr                         = PetscSectionGetOffset(ett,e,&off);CHKERRQ(ierr);
1723*0a96aa3bSJed Brown     conn->ett_offset[e - eStart] = (p4est_topidx_t) off;
1724*0a96aa3bSJed Brown     ierr                         = DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
1725*0a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
1726*0a96aa3bSJed Brown       PetscInt p = star[2 * s];
1727*0a96aa3bSJed Brown 
1728*0a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
1729*0a96aa3bSJed Brown         ierr = DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1730*0a96aa3bSJed Brown         if (closureSize != P4EST_INSUL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
1731*0a96aa3bSJed Brown         for (c = 0; c < P8EST_EDGES; c++) {
1732*0a96aa3bSJed Brown           PetscInt cellEdge = closure[2 * (c + edgeOff)];
1733*0a96aa3bSJed Brown           PetscInt cellOrnt = closure[2 * (c + edgeOff) + 1];
1734*0a96aa3bSJed Brown           DMPolytopeType ct;
1735*0a96aa3bSJed Brown 
1736*0a96aa3bSJed Brown           ierr = DMPlexGetCellType(dm, cellEdge, &ct);CHKERRQ(ierr);
1737*0a96aa3bSJed Brown           cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt);
1738*0a96aa3bSJed Brown           if (cellEdge == e) {
1739*0a96aa3bSJed Brown             PetscInt p4estEdge = PetscEdgeToP4estEdge[c];
1740*0a96aa3bSJed Brown             PetscInt totalOrient;
1741*0a96aa3bSJed Brown 
1742*0a96aa3bSJed Brown             /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */
1743*0a96aa3bSJed Brown             totalOrient = DihedralCompose(2,cellOrnt,DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge]));
1744*0a96aa3bSJed Brown             /* p4est orientations are positive: -2 => 1, -1 => 0 */
1745*0a96aa3bSJed Brown             totalOrient             = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient;
1746*0a96aa3bSJed Brown             conn->edge_to_tree[off] = (p4est_locidx_t) (p - cStart);
1747*0a96aa3bSJed Brown             /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standart (see
1748*0a96aa3bSJed Brown              * p8est_connectivity.h) */
1749*0a96aa3bSJed Brown             conn->edge_to_edge[off++] = (int8_t) p4estEdge + P8EST_EDGES * totalOrient;
1750*0a96aa3bSJed Brown             conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart;
1751*0a96aa3bSJed Brown           }
1752*0a96aa3bSJed Brown         }
1753*0a96aa3bSJed Brown         ierr = DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1754*0a96aa3bSJed Brown       }
1755*0a96aa3bSJed Brown     }
1756*0a96aa3bSJed Brown     ierr = DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
1757*0a96aa3bSJed Brown   }
1758*0a96aa3bSJed Brown   ierr = PetscSectionDestroy(&ett);CHKERRQ(ierr);
1759*0a96aa3bSJed Brown #endif
1760*0a96aa3bSJed Brown 
1761*0a96aa3bSJed Brown   /* 4: visit every vertex */
1762*0a96aa3bSJed Brown   conn->ctt_offset[0] = 0;
1763*0a96aa3bSJed Brown   for (v = vStart; v < vEnd; v++) {
1764*0a96aa3bSJed Brown     PetscInt off, s;
1765*0a96aa3bSJed Brown 
1766*0a96aa3bSJed Brown     ierr                         = PetscSectionGetOffset(ctt,v,&off);CHKERRQ(ierr);
1767*0a96aa3bSJed Brown     conn->ctt_offset[v - vStart] = (p4est_topidx_t) off;
1768*0a96aa3bSJed Brown     ierr                         = DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
1769*0a96aa3bSJed Brown     for (s = 0; s < starSize; s++) {
1770*0a96aa3bSJed Brown       PetscInt p = star[2 * s];
1771*0a96aa3bSJed Brown 
1772*0a96aa3bSJed Brown       if (p >= cStart && p < cEnd) {
1773*0a96aa3bSJed Brown         ierr = DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1774*0a96aa3bSJed Brown         if (closureSize != P4EST_INSUL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure");
1775*0a96aa3bSJed Brown         for (c = 0; c < P4EST_CHILDREN; c++) {
1776*0a96aa3bSJed Brown           PetscInt cellVert = closure[2 * (c + vertOff)];
1777*0a96aa3bSJed Brown 
1778*0a96aa3bSJed Brown           if (cellVert == v) {
1779*0a96aa3bSJed Brown             PetscInt p4estVert = PetscVertToP4estVert[c];
1780*0a96aa3bSJed Brown 
1781*0a96aa3bSJed Brown             conn->corner_to_tree[off]     = (p4est_locidx_t) (p - cStart);
1782*0a96aa3bSJed Brown             conn->corner_to_corner[off++] = (int8_t) p4estVert;
1783*0a96aa3bSJed Brown             conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart;
1784*0a96aa3bSJed Brown           }
1785*0a96aa3bSJed Brown         }
1786*0a96aa3bSJed Brown         ierr = DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
1787*0a96aa3bSJed Brown       }
1788*0a96aa3bSJed Brown     }
1789*0a96aa3bSJed Brown     ierr = DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
1790*0a96aa3bSJed Brown   }
1791*0a96aa3bSJed Brown   ierr = PetscSectionDestroy(&ctt);CHKERRQ(ierr);
1792*0a96aa3bSJed Brown 
1793*0a96aa3bSJed Brown   /* 5: Compute the coordinates */
1794*0a96aa3bSJed Brown   {
1795*0a96aa3bSJed Brown     PetscInt     coordDim;
1796*0a96aa3bSJed Brown     Vec          coordVec;
1797*0a96aa3bSJed Brown     PetscSection coordSec;
1798*0a96aa3bSJed Brown     PetscBool    localized;
1799*0a96aa3bSJed Brown 
1800*0a96aa3bSJed Brown     ierr = DMGetCoordinateDim(dm, &coordDim);CHKERRQ(ierr);
1801*0a96aa3bSJed Brown     ierr = DMGetCoordinatesLocal(dm, &coordVec);CHKERRQ(ierr);
1802*0a96aa3bSJed Brown     ierr = DMGetCoordinatesLocalizedLocal(dm, &localized);CHKERRQ(ierr);
1803*0a96aa3bSJed Brown     ierr = DMGetCoordinateSection(dm, &coordSec);CHKERRQ(ierr);
1804*0a96aa3bSJed Brown     for (c = cStart; c < cEnd; c++) {
1805*0a96aa3bSJed Brown       PetscInt    dof;
1806*0a96aa3bSJed Brown       PetscScalar *cellCoords = NULL;
1807*0a96aa3bSJed Brown 
1808*0a96aa3bSJed Brown       ierr = DMPlexVecGetClosure(dm, coordSec, coordVec, c, &dof, &cellCoords);CHKERRQ(ierr);
1809*0a96aa3bSJed Brown       if (!localized && dof != P4EST_CHILDREN * coordDim) SETERRQ3(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Need coordinates at the corners: (dof) %D != %D * %D (sdim)", dof, P4EST_CHILDREN, coordDim);
1810*0a96aa3bSJed Brown       for (v = 0; v < P4EST_CHILDREN; v++) {
1811*0a96aa3bSJed Brown         PetscInt i, lim = PetscMin(3, coordDim);
1812*0a96aa3bSJed Brown         PetscInt p4estVert = PetscVertToP4estVert[v];
1813*0a96aa3bSJed Brown 
1814*0a96aa3bSJed Brown         conn->tree_to_vertex[P4EST_CHILDREN * (c - cStart) + v] = P4EST_CHILDREN * (c - cStart) + v;
1815*0a96aa3bSJed Brown         /* p4est vertices are always embedded in R^3 */
1816*0a96aa3bSJed Brown         for (i = 0; i < 3; i++)   conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = 0.;
1817*0a96aa3bSJed Brown         for (i = 0; i < lim; i++) conn->vertices[3 * (P4EST_CHILDREN * (c - cStart) + p4estVert) + i] = PetscRealPart(cellCoords[v * coordDim + i]);
1818*0a96aa3bSJed Brown       }
1819*0a96aa3bSJed Brown       ierr = DMPlexVecRestoreClosure(dm, coordSec, coordVec, c, &dof, &cellCoords);CHKERRQ(ierr);
1820*0a96aa3bSJed Brown     }
1821*0a96aa3bSJed Brown   }
1822*0a96aa3bSJed Brown 
1823*0a96aa3bSJed Brown #if defined(P4EST_ENABLE_DEBUG)
1824*0a96aa3bSJed Brown   if (!p4est_connectivity_is_valid(conn)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Plex to p4est conversion failed");
1825*0a96aa3bSJed Brown #endif
1826*0a96aa3bSJed Brown 
1827*0a96aa3bSJed Brown   *connOut = conn;
1828*0a96aa3bSJed Brown 
1829*0a96aa3bSJed Brown   *tree_face_to_uniq = ttf;
1830*0a96aa3bSJed Brown 
1831*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1832*0a96aa3bSJed Brown }
1833*0a96aa3bSJed Brown 
1834*0a96aa3bSJed Brown static PetscErrorCode locidx_to_PetscInt(sc_array_t * array)
1835*0a96aa3bSJed Brown {
1836*0a96aa3bSJed Brown   sc_array_t *newarray;
1837*0a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
1838*0a96aa3bSJed Brown 
1839*0a96aa3bSJed Brown   PetscFunctionBegin;
1840*0a96aa3bSJed Brown   if (array->elem_size != sizeof(p4est_locidx_t)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
1841*0a96aa3bSJed Brown 
1842*0a96aa3bSJed Brown   if (sizeof(p4est_locidx_t) == sizeof(PetscInt)) PetscFunctionReturn(0);
1843*0a96aa3bSJed Brown 
1844*0a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscInt), array->elem_count);
1845*0a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
1846*0a96aa3bSJed Brown     p4est_locidx_t il  = *((p4est_locidx_t*) sc_array_index (array, zz));
1847*0a96aa3bSJed Brown     PetscInt       *ip = (PetscInt*) sc_array_index (newarray, zz);
1848*0a96aa3bSJed Brown 
1849*0a96aa3bSJed Brown     *ip = (PetscInt) il;
1850*0a96aa3bSJed Brown   }
1851*0a96aa3bSJed Brown 
1852*0a96aa3bSJed Brown   sc_array_reset (array);
1853*0a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscInt), count);
1854*0a96aa3bSJed Brown   sc_array_copy (array, newarray);
1855*0a96aa3bSJed Brown   sc_array_destroy (newarray);
1856*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1857*0a96aa3bSJed Brown }
1858*0a96aa3bSJed Brown 
1859*0a96aa3bSJed Brown static PetscErrorCode coords_double_to_PetscScalar(sc_array_t * array, PetscInt dim)
1860*0a96aa3bSJed Brown {
1861*0a96aa3bSJed Brown   sc_array_t *newarray;
1862*0a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
1863*0a96aa3bSJed Brown 
1864*0a96aa3bSJed Brown   PetscFunctionBegin;
1865*0a96aa3bSJed Brown   if (array->elem_size != 3 * sizeof(double)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong coordinate size");
1866*0a96aa3bSJed Brown #if !defined(PETSC_USE_COMPLEX)
1867*0a96aa3bSJed Brown   if (sizeof(double) == sizeof(PetscScalar) && dim == 3) PetscFunctionReturn(0);
1868*0a96aa3bSJed Brown #endif
1869*0a96aa3bSJed Brown 
1870*0a96aa3bSJed Brown   newarray = sc_array_new_size (dim * sizeof(PetscScalar), array->elem_count);
1871*0a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
1872*0a96aa3bSJed Brown     int         i;
1873*0a96aa3bSJed Brown     double      *id = (double*) sc_array_index (array, zz);
1874*0a96aa3bSJed Brown     PetscScalar *ip = (PetscScalar*) sc_array_index (newarray, zz);
1875*0a96aa3bSJed Brown 
1876*0a96aa3bSJed Brown     for (i = 0; i < dim; i++) ip[i] = 0.;
1877*0a96aa3bSJed Brown     for (i = 0; i < PetscMin(dim,3); i++) ip[i] = (PetscScalar) id[i];
1878*0a96aa3bSJed Brown   }
1879*0a96aa3bSJed Brown 
1880*0a96aa3bSJed Brown   sc_array_reset (array);
1881*0a96aa3bSJed Brown   sc_array_init_size (array, dim * sizeof(PetscScalar), count);
1882*0a96aa3bSJed Brown   sc_array_copy (array, newarray);
1883*0a96aa3bSJed Brown   sc_array_destroy (newarray);
1884*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1885*0a96aa3bSJed Brown }
1886*0a96aa3bSJed Brown 
1887*0a96aa3bSJed Brown static PetscErrorCode locidx_pair_to_PetscSFNode(sc_array_t * array)
1888*0a96aa3bSJed Brown {
1889*0a96aa3bSJed Brown   sc_array_t *newarray;
1890*0a96aa3bSJed Brown   size_t     zz, count = array->elem_count;
1891*0a96aa3bSJed Brown 
1892*0a96aa3bSJed Brown   PetscFunctionBegin;
1893*0a96aa3bSJed Brown   if (array->elem_size != 2 * sizeof(p4est_locidx_t)) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Wrong locidx size");
1894*0a96aa3bSJed Brown 
1895*0a96aa3bSJed Brown   newarray = sc_array_new_size (sizeof(PetscSFNode), array->elem_count);
1896*0a96aa3bSJed Brown   for (zz = 0; zz < count; zz++) {
1897*0a96aa3bSJed Brown     p4est_locidx_t *il = (p4est_locidx_t*) sc_array_index (array, zz);
1898*0a96aa3bSJed Brown     PetscSFNode    *ip = (PetscSFNode*) sc_array_index (newarray, zz);
1899*0a96aa3bSJed Brown 
1900*0a96aa3bSJed Brown     ip->rank  = (PetscInt) il[0];
1901*0a96aa3bSJed Brown     ip->index = (PetscInt) il[1];
1902*0a96aa3bSJed Brown   }
1903*0a96aa3bSJed Brown 
1904*0a96aa3bSJed Brown   sc_array_reset (array);
1905*0a96aa3bSJed Brown   sc_array_init_size (array, sizeof(PetscSFNode), count);
1906*0a96aa3bSJed Brown   sc_array_copy (array, newarray);
1907*0a96aa3bSJed Brown   sc_array_destroy (newarray);
1908*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1909*0a96aa3bSJed Brown }
1910*0a96aa3bSJed Brown 
1911*0a96aa3bSJed Brown static PetscErrorCode P4estToPlex_Local(p4est_t *p4est, DM * plex)
1912*0a96aa3bSJed Brown {
1913*0a96aa3bSJed Brown   PetscErrorCode ierr;
1914*0a96aa3bSJed Brown 
1915*0a96aa3bSJed Brown   PetscFunctionBegin;
1916*0a96aa3bSJed Brown   {
1917*0a96aa3bSJed Brown     sc_array_t     *points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
1918*0a96aa3bSJed Brown     sc_array_t     *cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
1919*0a96aa3bSJed Brown     sc_array_t     *cones             = sc_array_new(sizeof(p4est_locidx_t));
1920*0a96aa3bSJed Brown     sc_array_t     *cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
1921*0a96aa3bSJed Brown     sc_array_t     *coords            = sc_array_new(3 * sizeof(double));
1922*0a96aa3bSJed Brown     sc_array_t     *children          = sc_array_new(sizeof(p4est_locidx_t));
1923*0a96aa3bSJed Brown     sc_array_t     *parents           = sc_array_new(sizeof(p4est_locidx_t));
1924*0a96aa3bSJed Brown     sc_array_t     *childids          = sc_array_new(sizeof(p4est_locidx_t));
1925*0a96aa3bSJed Brown     sc_array_t     *leaves            = sc_array_new(sizeof(p4est_locidx_t));
1926*0a96aa3bSJed Brown     sc_array_t     *remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
1927*0a96aa3bSJed Brown     p4est_locidx_t first_local_quad;
1928*0a96aa3bSJed Brown 
1929*0a96aa3bSJed 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));
1930*0a96aa3bSJed Brown 
1931*0a96aa3bSJed Brown     ierr = locidx_to_PetscInt(points_per_dim);CHKERRQ(ierr);
1932*0a96aa3bSJed Brown     ierr = locidx_to_PetscInt(cone_sizes);CHKERRQ(ierr);
1933*0a96aa3bSJed Brown     ierr = locidx_to_PetscInt(cones);CHKERRQ(ierr);
1934*0a96aa3bSJed Brown     ierr = locidx_to_PetscInt(cone_orientations);CHKERRQ(ierr);
1935*0a96aa3bSJed Brown     ierr = coords_double_to_PetscScalar(coords, P4EST_DIM);CHKERRQ(ierr);
1936*0a96aa3bSJed Brown 
1937*0a96aa3bSJed Brown     ierr = DMPlexCreate(PETSC_COMM_SELF,plex);CHKERRQ(ierr);
1938*0a96aa3bSJed Brown     ierr = DMSetDimension(*plex,P4EST_DIM);CHKERRQ(ierr);
1939*0a96aa3bSJed Brown     ierr = DMPlexCreateFromDAG(*plex,P4EST_DIM,(PetscInt*)points_per_dim->array,(PetscInt*)cone_sizes->array,(PetscInt*)cones->array,(PetscInt*)cone_orientations->array,(PetscScalar*)coords->array);CHKERRQ(ierr);
1940*0a96aa3bSJed Brown     ierr = DMPlexConvertOldOrientations_Internal(*plex);CHKERRQ(ierr);
1941*0a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
1942*0a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
1943*0a96aa3bSJed Brown     sc_array_destroy (cones);
1944*0a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
1945*0a96aa3bSJed Brown     sc_array_destroy (coords);
1946*0a96aa3bSJed Brown     sc_array_destroy (children);
1947*0a96aa3bSJed Brown     sc_array_destroy (parents);
1948*0a96aa3bSJed Brown     sc_array_destroy (childids);
1949*0a96aa3bSJed Brown     sc_array_destroy (leaves);
1950*0a96aa3bSJed Brown     sc_array_destroy (remotes);
1951*0a96aa3bSJed Brown   }
1952*0a96aa3bSJed Brown   PetscFunctionReturn(0);
1953*0a96aa3bSJed Brown }
1954*0a96aa3bSJed Brown 
1955*0a96aa3bSJed Brown #define DMReferenceTreeGetChildSymmetry_pforest _append_pforest(DMReferenceTreeGetChildSymmetry)
1956*0a96aa3bSJed Brown static PetscErrorCode DMReferenceTreeGetChildSymmetry_pforest(DM dm, PetscInt parent, PetscInt parentOrientA, PetscInt childOrientA, PetscInt childA, PetscInt parentOrientB, PetscInt *childOrientB,PetscInt *childB)
1957*0a96aa3bSJed Brown {
1958*0a96aa3bSJed Brown   PetscInt       coneSize, dStart, dEnd, vStart, vEnd, dim, ABswap, oAvert, oBvert, ABswapVert;
1959*0a96aa3bSJed Brown   PetscErrorCode ierr;
1960*0a96aa3bSJed Brown 
1961*0a96aa3bSJed Brown   PetscFunctionBegin;
1962*0a96aa3bSJed Brown   if (parentOrientA == parentOrientB) {
1963*0a96aa3bSJed Brown     if (childOrientB) *childOrientB = childOrientA;
1964*0a96aa3bSJed Brown     if (childB) *childB = childA;
1965*0a96aa3bSJed Brown     PetscFunctionReturn(0);
1966*0a96aa3bSJed Brown   }
1967*0a96aa3bSJed Brown   ierr = DMPlexGetDepthStratum(dm,0,&vStart,&vEnd);CHKERRQ(ierr);
1968*0a96aa3bSJed Brown   if (childA >= vStart && childA < vEnd) { /* vertices (always in the middle) are invarient under rotation */
1969*0a96aa3bSJed Brown     if (childOrientB) *childOrientB = 0;
1970*0a96aa3bSJed Brown     if (childB) *childB = childA;
1971*0a96aa3bSJed Brown     PetscFunctionReturn(0);
1972*0a96aa3bSJed Brown   }
1973*0a96aa3bSJed Brown   for (dim = 0; dim < 3; dim++) {
1974*0a96aa3bSJed Brown     ierr = DMPlexGetDepthStratum(dm,dim,&dStart,&dEnd);CHKERRQ(ierr);
1975*0a96aa3bSJed Brown     if (parent >= dStart && parent <= dEnd) break;
1976*0a96aa3bSJed Brown   }
1977*0a96aa3bSJed Brown   if (dim > 2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_SUP,"Cannot perform child symmetry for %d-cells",dim);
1978*0a96aa3bSJed Brown   if (!dim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"A vertex has no children");
1979*0a96aa3bSJed Brown   if (childA < dStart || childA >= dEnd) { /* a 1-cell in a 2-cell */
1980*0a96aa3bSJed Brown     /* this is a lower-dimensional child: bootstrap */
1981*0a96aa3bSJed Brown     PetscInt       size, i, sA = -1, sB, sOrientB, sConeSize;
1982*0a96aa3bSJed Brown     const PetscInt *supp, *coneA, *coneB, *oA, *oB;
1983*0a96aa3bSJed Brown 
1984*0a96aa3bSJed Brown     ierr = DMPlexGetSupportSize(dm,childA,&size);CHKERRQ(ierr);
1985*0a96aa3bSJed Brown     ierr = DMPlexGetSupport(dm,childA,&supp);CHKERRQ(ierr);
1986*0a96aa3bSJed Brown 
1987*0a96aa3bSJed Brown     /* find a point sA in supp(childA) that has the same parent */
1988*0a96aa3bSJed Brown     for (i = 0; i < size; i++) {
1989*0a96aa3bSJed Brown       PetscInt sParent;
1990*0a96aa3bSJed Brown 
1991*0a96aa3bSJed Brown       sA = supp[i];
1992*0a96aa3bSJed Brown       if (sA == parent) continue;
1993*0a96aa3bSJed Brown       ierr = DMPlexGetTreeParent(dm,sA,&sParent,NULL);CHKERRQ(ierr);
1994*0a96aa3bSJed Brown       if (sParent == parent) break;
1995*0a96aa3bSJed Brown     }
1996*0a96aa3bSJed Brown     if (i == size) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"could not find support in children");
1997*0a96aa3bSJed Brown     /* find out which point sB is in an equivalent position to sA under
1998*0a96aa3bSJed Brown      * parentOrientB */
1999*0a96aa3bSJed Brown     ierr = DMReferenceTreeGetChildSymmetry_pforest(dm,parent,parentOrientA,0,sA,parentOrientB,&sOrientB,&sB);CHKERRQ(ierr);
2000*0a96aa3bSJed Brown     ierr = DMPlexGetConeSize(dm,sA,&sConeSize);CHKERRQ(ierr);
2001*0a96aa3bSJed Brown     ierr = DMPlexGetCone(dm,sA,&coneA);CHKERRQ(ierr);
2002*0a96aa3bSJed Brown     ierr = DMPlexGetCone(dm,sB,&coneB);CHKERRQ(ierr);
2003*0a96aa3bSJed Brown     ierr = DMPlexGetConeOrientation(dm,sA,&oA);CHKERRQ(ierr);
2004*0a96aa3bSJed Brown     ierr = DMPlexGetConeOrientation(dm,sB,&oB);CHKERRQ(ierr);
2005*0a96aa3bSJed Brown     /* step through the cone of sA in natural order */
2006*0a96aa3bSJed Brown     for (i = 0; i < sConeSize; i++) {
2007*0a96aa3bSJed Brown       if (coneA[i] == childA) {
2008*0a96aa3bSJed Brown         /* if childA is at position i in coneA,
2009*0a96aa3bSJed Brown          * then we want the point that is at sOrientB*i in coneB */
2010*0a96aa3bSJed Brown         PetscInt j = (sOrientB >= 0) ? ((sOrientB + i) % sConeSize) : ((sConeSize -(sOrientB+1) - i) % sConeSize);
2011*0a96aa3bSJed Brown         if (childB) *childB = coneB[j];
2012*0a96aa3bSJed Brown         if (childOrientB) {
2013*0a96aa3bSJed Brown           DMPolytopeType ct;
2014*0a96aa3bSJed Brown           PetscInt       oBtrue;
2015*0a96aa3bSJed Brown 
2016*0a96aa3bSJed Brown           ierr = DMPlexGetConeSize(dm,childA,&coneSize);CHKERRQ(ierr);
2017*0a96aa3bSJed Brown           /* compose sOrientB and oB[j] */
2018*0a96aa3bSJed Brown           if (coneSize != 0 && coneSize != 2) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Expected a vertex or an edge");
2019*0a96aa3bSJed Brown           ct = coneSize ? DM_POLYTOPE_SEGMENT : DM_POLYTOPE_POINT;
2020*0a96aa3bSJed Brown           /* we may have to flip an edge */
2021*0a96aa3bSJed Brown           oBtrue        = (sOrientB >= 0) ? oB[j] : DMPolytopeTypeComposeOrientationInv(ct, -1, oB[j]);
2022*0a96aa3bSJed Brown           oBtrue        = DMPolytopeConvertNewOrientation_Internal(ct, oBtrue);
2023*0a96aa3bSJed Brown           ABswap        = DihedralSwap(coneSize,DMPolytopeConvertNewOrientation_Internal(ct, oA[i]),oBtrue);
2024*0a96aa3bSJed Brown           *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
2025*0a96aa3bSJed Brown         }
2026*0a96aa3bSJed Brown         break;
2027*0a96aa3bSJed Brown       }
2028*0a96aa3bSJed Brown     }
2029*0a96aa3bSJed Brown     if (i == sConeSize) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"support cone mismatch");
2030*0a96aa3bSJed Brown     PetscFunctionReturn(0);
2031*0a96aa3bSJed Brown   }
2032*0a96aa3bSJed Brown   /* get the cone size and symmetry swap */
2033*0a96aa3bSJed Brown   ierr   = DMPlexGetConeSize(dm,parent,&coneSize);CHKERRQ(ierr);
2034*0a96aa3bSJed Brown   ABswap = DihedralSwap(coneSize, parentOrientA, parentOrientB);
2035*0a96aa3bSJed Brown   if (dim == 2) {
2036*0a96aa3bSJed Brown     /* orientations refer to cones: we want them to refer to vertices:
2037*0a96aa3bSJed Brown      * if it's a rotation, they are the same, but if the order is reversed, a
2038*0a96aa3bSJed Brown      * permutation that puts side i first does *not* put vertex i first */
2039*0a96aa3bSJed Brown     oAvert     = (parentOrientA >= 0) ? parentOrientA : -((-parentOrientA % coneSize) + 1);
2040*0a96aa3bSJed Brown     oBvert     = (parentOrientB >= 0) ? parentOrientB : -((-parentOrientB % coneSize) + 1);
2041*0a96aa3bSJed Brown     ABswapVert = DihedralSwap(coneSize, oAvert, oBvert);
2042*0a96aa3bSJed Brown   } else {
2043*0a96aa3bSJed Brown     oAvert     = parentOrientA;
2044*0a96aa3bSJed Brown     oBvert     = parentOrientB;
2045*0a96aa3bSJed Brown     ABswapVert = ABswap;
2046*0a96aa3bSJed Brown   }
2047*0a96aa3bSJed Brown   if (childB) {
2048*0a96aa3bSJed Brown     /* assume that each child corresponds to a vertex, in the same order */
2049*0a96aa3bSJed Brown     PetscInt       p, posA = -1, numChildren, i;
2050*0a96aa3bSJed Brown     const PetscInt *children;
2051*0a96aa3bSJed Brown 
2052*0a96aa3bSJed Brown     /* count which position the child is in */
2053*0a96aa3bSJed Brown     ierr = DMPlexGetTreeChildren(dm,parent,&numChildren,&children);CHKERRQ(ierr);
2054*0a96aa3bSJed Brown     for (i = 0; i < numChildren; i++) {
2055*0a96aa3bSJed Brown       p = children[i];
2056*0a96aa3bSJed Brown       if (p == childA) {
2057*0a96aa3bSJed Brown         if (dim == 1) {
2058*0a96aa3bSJed Brown           posA = i;
2059*0a96aa3bSJed Brown         } else { /* 2D Morton to rotation */
2060*0a96aa3bSJed Brown           posA = (i & 2) ? (i ^ 1) : i;
2061*0a96aa3bSJed Brown         }
2062*0a96aa3bSJed Brown         break;
2063*0a96aa3bSJed Brown       }
2064*0a96aa3bSJed Brown     }
2065*0a96aa3bSJed Brown     if (posA >= coneSize) {
2066*0a96aa3bSJed Brown       SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Could not find childA in children of parent");
2067*0a96aa3bSJed Brown     } else {
2068*0a96aa3bSJed Brown       /* figure out position B by applying ABswapVert */
2069*0a96aa3bSJed Brown       PetscInt posB, childIdB;
2070*0a96aa3bSJed Brown 
2071*0a96aa3bSJed Brown       posB = (ABswapVert >= 0) ? ((ABswapVert + posA) % coneSize) : ((coneSize -(ABswapVert + 1) - posA) % coneSize);
2072*0a96aa3bSJed Brown       if (dim == 1) {
2073*0a96aa3bSJed Brown         childIdB = posB;
2074*0a96aa3bSJed Brown       } else { /* 2D rotation to Morton */
2075*0a96aa3bSJed Brown         childIdB = (posB & 2) ? (posB ^ 1) : posB;
2076*0a96aa3bSJed Brown       }
2077*0a96aa3bSJed Brown       if (childB) *childB = children[childIdB];
2078*0a96aa3bSJed Brown     }
2079*0a96aa3bSJed Brown   }
2080*0a96aa3bSJed Brown   if (childOrientB) *childOrientB = DihedralCompose(coneSize,childOrientA,ABswap);
2081*0a96aa3bSJed Brown   PetscFunctionReturn(0);
2082*0a96aa3bSJed Brown }
2083*0a96aa3bSJed Brown 
2084*0a96aa3bSJed Brown #define DMCreateReferenceTree_pforest _append_pforest(DMCreateReferenceTree)
2085*0a96aa3bSJed Brown static PetscErrorCode DMCreateReferenceTree_pforest(MPI_Comm comm, DM *dm)
2086*0a96aa3bSJed Brown {
2087*0a96aa3bSJed Brown   p4est_connectivity_t *refcube;
2088*0a96aa3bSJed Brown   p4est_t              *root, *refined;
2089*0a96aa3bSJed Brown   DM                   dmRoot, dmRefined;
2090*0a96aa3bSJed Brown   DM_Plex              *mesh;
2091*0a96aa3bSJed Brown   PetscMPIInt          rank;
2092*0a96aa3bSJed Brown   PetscErrorCode       ierr;
2093*0a96aa3bSJed Brown 
2094*0a96aa3bSJed Brown   PetscFunctionBegin;
2095*0a96aa3bSJed Brown   PetscStackCallP4estReturn(refcube,p4est_connectivity_new_byname,("unit"));
2096*0a96aa3bSJed Brown   { /* [-1,1]^d geometry */
2097*0a96aa3bSJed Brown     PetscInt i, j;
2098*0a96aa3bSJed Brown 
2099*0a96aa3bSJed Brown     for (i = 0; i < P4EST_CHILDREN; i++) {
2100*0a96aa3bSJed Brown       for (j = 0; j < 3; j++) {
2101*0a96aa3bSJed Brown         refcube->vertices[3 * i + j] *= 2.;
2102*0a96aa3bSJed Brown         refcube->vertices[3 * i + j] -= 1.;
2103*0a96aa3bSJed Brown       }
2104*0a96aa3bSJed Brown     }
2105*0a96aa3bSJed Brown   }
2106*0a96aa3bSJed Brown   PetscStackCallP4estReturn(root,p4est_new,(PETSC_COMM_SELF,refcube,0,NULL,NULL));
2107*0a96aa3bSJed Brown   PetscStackCallP4estReturn(refined,p4est_new_ext,(PETSC_COMM_SELF,refcube,0,1,1,0,NULL,NULL));
2108*0a96aa3bSJed Brown   ierr = P4estToPlex_Local(root,&dmRoot);CHKERRQ(ierr);
2109*0a96aa3bSJed Brown   ierr = P4estToPlex_Local(refined,&dmRefined);CHKERRQ(ierr);
2110*0a96aa3bSJed Brown   {
2111*0a96aa3bSJed Brown #if !defined(P4_TO_P8)
2112*0a96aa3bSJed Brown     PetscInt nPoints  = 25;
2113*0a96aa3bSJed Brown     PetscInt perm[25] = {0, 1, 2, 3,
2114*0a96aa3bSJed Brown                           4, 12, 8, 14,
2115*0a96aa3bSJed Brown                               6, 9, 15,
2116*0a96aa3bSJed Brown                           5, 13,    10,
2117*0a96aa3bSJed Brown                               7,    11,
2118*0a96aa3bSJed Brown                          16, 22, 20, 24,
2119*0a96aa3bSJed Brown                              17,     21,
2120*0a96aa3bSJed Brown                                  18, 23,
2121*0a96aa3bSJed Brown                                      19};
2122*0a96aa3bSJed Brown     PetscInt ident[25] = {0, 0, 0, 0,
2123*0a96aa3bSJed Brown                           1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0,
2124*0a96aa3bSJed Brown                           5, 6, 7, 8, 1, 2, 3, 4, 0};
2125*0a96aa3bSJed Brown #else
2126*0a96aa3bSJed Brown     PetscInt nPoints   = 125;
2127*0a96aa3bSJed Brown     PetscInt perm[125] = {0, 1, 2, 3, 4, 5, 6, 7,
2128*0a96aa3bSJed Brown                            8, 32, 16, 36, 24, 40,
2129*0a96aa3bSJed Brown                               12, 17, 37, 25, 41,
2130*0a96aa3bSJed Brown                            9, 33,     20, 26, 42,
2131*0a96aa3bSJed Brown                               13,     21, 27, 43,
2132*0a96aa3bSJed Brown                           10, 34, 18, 38,     28,
2133*0a96aa3bSJed Brown                               14, 19, 39,     29,
2134*0a96aa3bSJed Brown                           11, 35,     22,     30,
2135*0a96aa3bSJed Brown                               15,     23,     31,
2136*0a96aa3bSJed Brown                           44, 84, 76, 92, 52, 86, 68, 94, 60, 78, 70, 96,
2137*0a96aa3bSJed Brown                           45, 85, 77, 93,     54,     72,     62,     74,
2138*0a96aa3bSJed Brown                               46,     80, 53, 87, 69, 95,         64, 82,
2139*0a96aa3bSJed Brown                               47,     81,     55,     73,             66,
2140*0a96aa3bSJed Brown                                   48, 88,         56, 90, 61, 79, 71, 97,
2141*0a96aa3bSJed Brown                                   49, 89,             58,     63,     75,
2142*0a96aa3bSJed Brown                                       50,         57, 91,         65, 83,
2143*0a96aa3bSJed Brown                                       51,             59,             67,
2144*0a96aa3bSJed Brown                            98, 106, 110, 122, 114, 120, 118, 124,
2145*0a96aa3bSJed Brown                                 99,      111,      115,      119,
2146*0a96aa3bSJed Brown                                     100, 107,           116, 121,
2147*0a96aa3bSJed Brown                                          101,                117,
2148*0a96aa3bSJed Brown                                               102, 108, 112, 123,
2149*0a96aa3bSJed Brown                                                    103,      113,
2150*0a96aa3bSJed Brown                                                         104, 109,
2151*0a96aa3bSJed Brown                                                              105};
2152*0a96aa3bSJed Brown     PetscInt ident[125] = {0, 0, 0, 0, 0, 0, 0, 0,
2153*0a96aa3bSJed 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,
2154*0a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
2155*0a96aa3bSJed 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,
2156*0a96aa3bSJed 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,
2157*0a96aa3bSJed Brown                            0, 0, 0, 0, 0, 0,
2158*0a96aa3bSJed Brown                            19, 20, 21, 22, 23, 24, 25, 26,
2159*0a96aa3bSJed Brown                            7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
2160*0a96aa3bSJed Brown                            1, 2, 3, 4, 5, 6,
2161*0a96aa3bSJed Brown                            0};
2162*0a96aa3bSJed Brown 
2163*0a96aa3bSJed Brown #endif
2164*0a96aa3bSJed Brown     IS permIS;
2165*0a96aa3bSJed Brown     DM dmPerm;
2166*0a96aa3bSJed Brown 
2167*0a96aa3bSJed Brown     ierr = ISCreateGeneral(PETSC_COMM_SELF,nPoints,perm,PETSC_USE_POINTER,&permIS);CHKERRQ(ierr);
2168*0a96aa3bSJed Brown     ierr = DMPlexPermute(dmRefined,permIS,&dmPerm);CHKERRQ(ierr);
2169*0a96aa3bSJed Brown     if (dmPerm) {
2170*0a96aa3bSJed Brown       ierr      = DMDestroy(&dmRefined);CHKERRQ(ierr);
2171*0a96aa3bSJed Brown       dmRefined = dmPerm;
2172*0a96aa3bSJed Brown     }
2173*0a96aa3bSJed Brown     ierr = ISDestroy(&permIS);CHKERRQ(ierr);
2174*0a96aa3bSJed Brown     {
2175*0a96aa3bSJed Brown       PetscInt p;
2176*0a96aa3bSJed Brown       ierr = DMCreateLabel(dmRoot,"identity");CHKERRQ(ierr);
2177*0a96aa3bSJed Brown       ierr = DMCreateLabel(dmRefined,"identity");CHKERRQ(ierr);
2178*0a96aa3bSJed Brown       for (p = 0; p < P4EST_INSUL; p++) {
2179*0a96aa3bSJed Brown         ierr = DMSetLabelValue(dmRoot,"identity",p,p);CHKERRQ(ierr);
2180*0a96aa3bSJed Brown       }
2181*0a96aa3bSJed Brown       for (p = 0; p < nPoints; p++) {
2182*0a96aa3bSJed Brown         ierr = DMSetLabelValue(dmRefined,"identity",p,ident[p]);CHKERRQ(ierr);
2183*0a96aa3bSJed Brown       }
2184*0a96aa3bSJed Brown     }
2185*0a96aa3bSJed Brown   }
2186*0a96aa3bSJed Brown   ierr                   = DMPlexCreateReferenceTree_Union(dmRoot,dmRefined,"identity",dm);CHKERRQ(ierr);
2187*0a96aa3bSJed Brown   mesh                   = (DM_Plex*) (*dm)->data;
2188*0a96aa3bSJed Brown   mesh->getchildsymmetry = DMReferenceTreeGetChildSymmetry_pforest;
2189*0a96aa3bSJed Brown   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
2190*0a96aa3bSJed Brown   if (rank == 0) {
2191*0a96aa3bSJed Brown     ierr = DMViewFromOptions(dmRoot,   NULL,"-dm_p4est_ref_root_view");CHKERRQ(ierr);
2192*0a96aa3bSJed Brown     ierr = DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_refined_view");CHKERRQ(ierr);
2193*0a96aa3bSJed Brown     ierr = DMViewFromOptions(dmRefined,NULL,"-dm_p4est_ref_tree_view");CHKERRQ(ierr);
2194*0a96aa3bSJed Brown   }
2195*0a96aa3bSJed Brown   ierr                   = DMDestroy(&dmRefined);CHKERRQ(ierr);
2196*0a96aa3bSJed Brown   ierr                   = DMDestroy(&dmRoot);CHKERRQ(ierr);
2197*0a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(refined));
2198*0a96aa3bSJed Brown   PetscStackCallP4est(p4est_destroy,(root));
2199*0a96aa3bSJed Brown   PetscStackCallP4est(p4est_connectivity_destroy,(refcube));
2200*0a96aa3bSJed Brown   PetscFunctionReturn(0);
2201*0a96aa3bSJed Brown }
2202*0a96aa3bSJed Brown 
2203*0a96aa3bSJed Brown static PetscErrorCode DMShareDiscretization(DM dmA, DM dmB)
2204*0a96aa3bSJed Brown {
2205*0a96aa3bSJed Brown   void          *ctx;
2206*0a96aa3bSJed Brown   PetscInt       num;
2207*0a96aa3bSJed Brown   PetscReal      val;
2208*0a96aa3bSJed Brown   PetscErrorCode ierr;
2209*0a96aa3bSJed Brown 
2210*0a96aa3bSJed Brown   PetscFunctionBegin;
2211*0a96aa3bSJed Brown   ierr  = DMGetApplicationContext(dmA,&ctx);CHKERRQ(ierr);
2212*0a96aa3bSJed Brown   ierr  = DMSetApplicationContext(dmB,ctx);CHKERRQ(ierr);
2213*0a96aa3bSJed Brown   ierr  = DMCopyDisc(dmA,dmB);CHKERRQ(ierr);
2214*0a96aa3bSJed Brown   ierr  = DMGetOutputSequenceNumber(dmA,&num,&val);CHKERRQ(ierr);
2215*0a96aa3bSJed Brown   ierr  = DMSetOutputSequenceNumber(dmB,num,val);CHKERRQ(ierr);
2216*0a96aa3bSJed Brown   if (dmB->localSection != dmA->localSection || dmB->globalSection != dmA->globalSection) {
2217*0a96aa3bSJed Brown     ierr = DMClearLocalVectors(dmB);CHKERRQ(ierr);
2218*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)dmA->localSection);CHKERRQ(ierr);
2219*0a96aa3bSJed Brown     ierr = PetscSectionDestroy(&(dmB->localSection));CHKERRQ(ierr);
2220*0a96aa3bSJed Brown     dmB->localSection = dmA->localSection;
2221*0a96aa3bSJed Brown     ierr = DMClearGlobalVectors(dmB);CHKERRQ(ierr);
2222*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)dmA->globalSection);CHKERRQ(ierr);
2223*0a96aa3bSJed Brown     ierr = PetscSectionDestroy(&(dmB->globalSection));CHKERRQ(ierr);
2224*0a96aa3bSJed Brown     dmB->globalSection = dmA->globalSection;
2225*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)dmA->defaultConstraintSection);CHKERRQ(ierr);
2226*0a96aa3bSJed Brown     ierr = PetscSectionDestroy(&(dmB->defaultConstraintSection));CHKERRQ(ierr);
2227*0a96aa3bSJed Brown     dmB->defaultConstraintSection = dmA->defaultConstraintSection;
2228*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)dmA->defaultConstraintMat);CHKERRQ(ierr);
2229*0a96aa3bSJed Brown     ierr = MatDestroy(&(dmB->defaultConstraintMat));CHKERRQ(ierr);
2230*0a96aa3bSJed Brown     dmB->defaultConstraintMat = dmA->defaultConstraintMat;
2231*0a96aa3bSJed Brown     if (dmA->map) {ierr = PetscLayoutReference(dmA->map, &dmB->map);CHKERRQ(ierr);}
2232*0a96aa3bSJed Brown   }
2233*0a96aa3bSJed Brown   if (dmB->sectionSF != dmA->sectionSF) {
2234*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)dmA->sectionSF);CHKERRQ(ierr);
2235*0a96aa3bSJed Brown     ierr = PetscSFDestroy(&dmB->sectionSF);CHKERRQ(ierr);
2236*0a96aa3bSJed Brown     dmB->sectionSF = dmA->sectionSF;
2237*0a96aa3bSJed Brown   }
2238*0a96aa3bSJed Brown   PetscFunctionReturn(0);
2239*0a96aa3bSJed Brown }
2240*0a96aa3bSJed Brown 
2241*0a96aa3bSJed Brown /* Get an SF that broadcasts a coarse-cell covering of the local fine cells */
2242*0a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellCoveringSF(MPI_Comm comm,p4est_t *p4estC, p4est_t *p4estF, PetscInt cStart, PetscInt cEnd, PetscSF *coveringSF)
2243*0a96aa3bSJed Brown {
2244*0a96aa3bSJed Brown   PetscInt       startF, endF, startC, endC, p, nLeaves;
2245*0a96aa3bSJed Brown   PetscSFNode    *leaves;
2246*0a96aa3bSJed Brown   PetscSF        sf;
2247*0a96aa3bSJed Brown   PetscInt       *recv, *send;
2248*0a96aa3bSJed Brown   PetscMPIInt    tag;
2249*0a96aa3bSJed Brown   MPI_Request    *recvReqs, *sendReqs;
2250*0a96aa3bSJed Brown   PetscSection   section;
2251*0a96aa3bSJed Brown   PetscErrorCode ierr;
2252*0a96aa3bSJed Brown 
2253*0a96aa3bSJed Brown   PetscFunctionBegin;
2254*0a96aa3bSJed Brown   ierr = DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estF,p4estC,&startC,&endC);CHKERRQ(ierr);
2255*0a96aa3bSJed Brown   ierr = PetscMalloc2(2*(endC-startC),&recv,endC-startC,&recvReqs);CHKERRQ(ierr);
2256*0a96aa3bSJed Brown   ierr = PetscCommGetNewTag(comm,&tag);CHKERRQ(ierr);
2257*0a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
2258*0a96aa3bSJed Brown     recvReqs[p-startC] = MPI_REQUEST_NULL; /* just in case we don't initiate a receive */
2259*0a96aa3bSJed Brown     if (p4estC->global_first_quadrant[p] == p4estC->global_first_quadrant[p+1]) { /* empty coarse partition */
2260*0a96aa3bSJed Brown       recv[2*(p-startC)]   = 0;
2261*0a96aa3bSJed Brown       recv[2*(p-startC)+1] = 0;
2262*0a96aa3bSJed Brown       continue;
2263*0a96aa3bSJed Brown     }
2264*0a96aa3bSJed Brown 
2265*0a96aa3bSJed Brown     ierr = MPI_Irecv(&recv[2*(p-startC)],2,MPIU_INT,p,tag,comm,&recvReqs[p-startC]);CHKERRMPI(ierr);
2266*0a96aa3bSJed Brown   }
2267*0a96aa3bSJed Brown   ierr = DMPforestComputeOverlappingRanks(p4estC->mpisize,p4estC->mpirank,p4estC,p4estF,&startF,&endF);CHKERRQ(ierr);
2268*0a96aa3bSJed Brown   ierr = PetscMalloc2(2*(endF-startF),&send,endF-startF,&sendReqs);CHKERRQ(ierr);
2269*0a96aa3bSJed Brown   /* count the quadrants rank will send to each of [startF,endF) */
2270*0a96aa3bSJed Brown   for (p = startF; p < endF; p++) {
2271*0a96aa3bSJed Brown     p4est_quadrant_t *myFineStart = &p4estF->global_first_position[p];
2272*0a96aa3bSJed Brown     p4est_quadrant_t *myFineEnd   = &p4estF->global_first_position[p+1];
2273*0a96aa3bSJed Brown     PetscInt         tStart       = (PetscInt) myFineStart->p.which_tree;
2274*0a96aa3bSJed Brown     PetscInt         tEnd         = (PetscInt) myFineEnd->p.which_tree;
2275*0a96aa3bSJed Brown     PetscInt         firstCell    = -1, lastCell = -1;
2276*0a96aa3bSJed Brown     p4est_tree_t     *treeStart   = &(((p4est_tree_t*) p4estC->trees->array)[tStart]);
2277*0a96aa3bSJed Brown     p4est_tree_t     *treeEnd     = (size_t) tEnd < p4estC->trees->elem_count ? &(((p4est_tree_t*) p4estC->trees->array)[tEnd]) : NULL;
2278*0a96aa3bSJed Brown     ssize_t          overlapIndex;
2279*0a96aa3bSJed Brown 
2280*0a96aa3bSJed Brown     sendReqs[p-startF] = MPI_REQUEST_NULL; /* just in case we don't initiate a send */
2281*0a96aa3bSJed Brown     if (p4estF->global_first_quadrant[p] == p4estF->global_first_quadrant[p+1]) continue;
2282*0a96aa3bSJed Brown 
2283*0a96aa3bSJed Brown     /* locate myFineStart in (or before) a cell */
2284*0a96aa3bSJed Brown     if (treeStart->quadrants.elem_count) {
2285*0a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeStart->quadrants),myFineStart,p4est_quadrant_disjoint));
2286*0a96aa3bSJed Brown       if (overlapIndex < 0) {
2287*0a96aa3bSJed Brown         firstCell = 0;
2288*0a96aa3bSJed Brown       } else {
2289*0a96aa3bSJed Brown         firstCell = treeStart->quadrants_offset + overlapIndex;
2290*0a96aa3bSJed Brown       }
2291*0a96aa3bSJed Brown     } else {
2292*0a96aa3bSJed Brown       firstCell = 0;
2293*0a96aa3bSJed Brown     }
2294*0a96aa3bSJed Brown     if (treeEnd && treeEnd->quadrants.elem_count) {
2295*0a96aa3bSJed Brown       PetscStackCallP4estReturn(overlapIndex,sc_array_bsearch,(&(treeEnd->quadrants),myFineEnd,p4est_quadrant_disjoint));
2296*0a96aa3bSJed Brown       if (overlapIndex < 0) { /* all of this local section is overlapped */
2297*0a96aa3bSJed Brown         lastCell = p4estC->local_num_quadrants;
2298*0a96aa3bSJed Brown       } else {
2299*0a96aa3bSJed Brown         p4est_quadrant_t *container = &(((p4est_quadrant_t*) treeEnd->quadrants.array)[overlapIndex]);
2300*0a96aa3bSJed Brown         p4est_quadrant_t first_desc;
2301*0a96aa3bSJed Brown         int              equal;
2302*0a96aa3bSJed Brown 
2303*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_first_descendant,(container,&first_desc,P4EST_QMAXLEVEL));
2304*0a96aa3bSJed Brown         PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(myFineEnd,&first_desc));
2305*0a96aa3bSJed Brown         if (equal) {
2306*0a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex;
2307*0a96aa3bSJed Brown         } else {
2308*0a96aa3bSJed Brown           lastCell = treeEnd->quadrants_offset + overlapIndex + 1;
2309*0a96aa3bSJed Brown         }
2310*0a96aa3bSJed Brown       }
2311*0a96aa3bSJed Brown     } else {
2312*0a96aa3bSJed Brown       lastCell = p4estC->local_num_quadrants;
2313*0a96aa3bSJed Brown     }
2314*0a96aa3bSJed Brown     send[2*(p-startF)]   = firstCell;
2315*0a96aa3bSJed Brown     send[2*(p-startF)+1] = lastCell - firstCell;
2316*0a96aa3bSJed Brown     ierr                 = MPI_Isend(&send[2*(p-startF)],2,MPIU_INT,p,tag,comm,&sendReqs[p-startF]);CHKERRMPI(ierr);
2317*0a96aa3bSJed Brown   }
2318*0a96aa3bSJed Brown   ierr = MPI_Waitall((PetscMPIInt)(endC-startC),recvReqs,MPI_STATUSES_IGNORE);CHKERRMPI(ierr);
2319*0a96aa3bSJed Brown   ierr = PetscSectionCreate(PETSC_COMM_SELF,&section);CHKERRQ(ierr);
2320*0a96aa3bSJed Brown   ierr = PetscSectionSetChart(section,startC,endC);CHKERRQ(ierr);
2321*0a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
2322*0a96aa3bSJed Brown     PetscInt numCells = recv[2*(p-startC)+1];
2323*0a96aa3bSJed Brown     ierr = PetscSectionSetDof(section,p,numCells);CHKERRQ(ierr);
2324*0a96aa3bSJed Brown   }
2325*0a96aa3bSJed Brown   ierr = PetscSectionSetUp(section);CHKERRQ(ierr);
2326*0a96aa3bSJed Brown   ierr = PetscSectionGetStorageSize(section,&nLeaves);CHKERRQ(ierr);
2327*0a96aa3bSJed Brown   ierr = PetscMalloc1(nLeaves,&leaves);CHKERRQ(ierr);
2328*0a96aa3bSJed Brown   for (p = startC; p < endC; p++) {
2329*0a96aa3bSJed Brown     PetscInt firstCell = recv[2*(p-startC)];
2330*0a96aa3bSJed Brown     PetscInt numCells  = recv[2*(p-startC)+1];
2331*0a96aa3bSJed Brown     PetscInt off, i;
2332*0a96aa3bSJed Brown 
2333*0a96aa3bSJed Brown     ierr = PetscSectionGetOffset(section,p,&off);CHKERRQ(ierr);
2334*0a96aa3bSJed Brown     for (i = 0; i < numCells; i++) {
2335*0a96aa3bSJed Brown       leaves[off+i].rank  = p;
2336*0a96aa3bSJed Brown       leaves[off+i].index = firstCell + i;
2337*0a96aa3bSJed Brown     }
2338*0a96aa3bSJed Brown   }
2339*0a96aa3bSJed Brown   ierr        = PetscSFCreate(comm,&sf);CHKERRQ(ierr);
2340*0a96aa3bSJed Brown   ierr        = PetscSFSetGraph(sf,cEnd-cStart,nLeaves,NULL,PETSC_OWN_POINTER,leaves,PETSC_OWN_POINTER);CHKERRQ(ierr);
2341*0a96aa3bSJed Brown   ierr        = PetscSectionDestroy(&section);CHKERRQ(ierr);
2342*0a96aa3bSJed Brown   ierr        = MPI_Waitall((PetscMPIInt)(endF-startF),sendReqs,MPI_STATUSES_IGNORE);CHKERRMPI(ierr);
2343*0a96aa3bSJed Brown   ierr        = PetscFree2(send,sendReqs);CHKERRQ(ierr);
2344*0a96aa3bSJed Brown   ierr        = PetscFree2(recv,recvReqs);CHKERRQ(ierr);
2345*0a96aa3bSJed Brown   *coveringSF = sf;
2346*0a96aa3bSJed Brown   PetscFunctionReturn(0);
2347*0a96aa3bSJed Brown }
2348*0a96aa3bSJed Brown 
2349*0a96aa3bSJed Brown /* closure points for locally-owned cells */
2350*0a96aa3bSJed Brown static PetscErrorCode DMPforestGetCellSFNodes(DM dm, PetscInt numClosureIndices, PetscInt *numClosurePoints, PetscSFNode **closurePoints,PetscBool redirect)
2351*0a96aa3bSJed Brown {
2352*0a96aa3bSJed Brown   PetscInt          cStart, cEnd;
2353*0a96aa3bSJed Brown   PetscInt          count, c;
2354*0a96aa3bSJed Brown   PetscMPIInt       rank;
2355*0a96aa3bSJed Brown   PetscInt          closureSize = -1;
2356*0a96aa3bSJed Brown   PetscInt          *closure    = NULL;
2357*0a96aa3bSJed Brown   PetscSF           pointSF;
2358*0a96aa3bSJed Brown   PetscInt          nleaves, nroots;
2359*0a96aa3bSJed Brown   const PetscInt    *ilocal;
2360*0a96aa3bSJed Brown   const PetscSFNode *iremote;
2361*0a96aa3bSJed Brown   DM                plex;
2362*0a96aa3bSJed Brown   DM_Forest         *forest;
2363*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
2364*0a96aa3bSJed Brown   PetscErrorCode    ierr;
2365*0a96aa3bSJed Brown 
2366*0a96aa3bSJed Brown   PetscFunctionBegin;
2367*0a96aa3bSJed Brown   forest            = (DM_Forest *) dm->data;
2368*0a96aa3bSJed Brown   pforest           = (DM_Forest_pforest *) forest->data;
2369*0a96aa3bSJed Brown   cStart            = pforest->cLocalStart;
2370*0a96aa3bSJed Brown   cEnd              = pforest->cLocalEnd;
2371*0a96aa3bSJed Brown   ierr              = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
2372*0a96aa3bSJed Brown   ierr              = DMGetPointSF(dm,&pointSF);CHKERRQ(ierr);
2373*0a96aa3bSJed Brown   ierr              = PetscSFGetGraph(pointSF,&nroots,&nleaves,&ilocal,&iremote);CHKERRQ(ierr);
2374*0a96aa3bSJed Brown   nleaves           = PetscMax(0,nleaves);
2375*0a96aa3bSJed Brown   nroots            = PetscMax(0,nroots);
2376*0a96aa3bSJed Brown   *numClosurePoints = numClosureIndices * (cEnd - cStart);
2377*0a96aa3bSJed Brown   ierr              = PetscMalloc1(*numClosurePoints,closurePoints);CHKERRQ(ierr);
2378*0a96aa3bSJed Brown   ierr              = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRMPI(ierr);
2379*0a96aa3bSJed Brown   for (c = cStart, count = 0; c < cEnd; c++) {
2380*0a96aa3bSJed Brown     PetscInt i;
2381*0a96aa3bSJed Brown     ierr = DMPlexGetTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2382*0a96aa3bSJed Brown 
2383*0a96aa3bSJed Brown     for (i = 0; i < numClosureIndices; i++, count++) {
2384*0a96aa3bSJed Brown       PetscInt p   = closure[2 * i];
2385*0a96aa3bSJed Brown       PetscInt loc = -1;
2386*0a96aa3bSJed Brown 
2387*0a96aa3bSJed Brown       ierr = PetscFindInt(p,nleaves,ilocal,&loc);CHKERRQ(ierr);
2388*0a96aa3bSJed Brown       if (redirect && loc >= 0) {
2389*0a96aa3bSJed Brown         (*closurePoints)[count].rank  = iremote[loc].rank;
2390*0a96aa3bSJed Brown         (*closurePoints)[count].index = iremote[loc].index;
2391*0a96aa3bSJed Brown       } else {
2392*0a96aa3bSJed Brown         (*closurePoints)[count].rank  = rank;
2393*0a96aa3bSJed Brown         (*closurePoints)[count].index = p;
2394*0a96aa3bSJed Brown       }
2395*0a96aa3bSJed Brown     }
2396*0a96aa3bSJed Brown     ierr = DMPlexRestoreTransitiveClosure(plex,c,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
2397*0a96aa3bSJed Brown   }
2398*0a96aa3bSJed Brown   PetscFunctionReturn(0);
2399*0a96aa3bSJed Brown }
2400*0a96aa3bSJed Brown 
2401*0a96aa3bSJed Brown static void MPIAPI DMPforestMaxSFNode(void *a, void *b, PetscMPIInt *len, MPI_Datatype *type)
2402*0a96aa3bSJed Brown {
2403*0a96aa3bSJed Brown   PetscMPIInt i;
2404*0a96aa3bSJed Brown 
2405*0a96aa3bSJed Brown   for (i = 0; i < *len; i++) {
2406*0a96aa3bSJed Brown     PetscSFNode *A = (PetscSFNode*)a;
2407*0a96aa3bSJed Brown     PetscSFNode *B = (PetscSFNode*)b;
2408*0a96aa3bSJed Brown 
2409*0a96aa3bSJed Brown     if (B->rank < 0) *B = *A;
2410*0a96aa3bSJed Brown   }
2411*0a96aa3bSJed Brown }
2412*0a96aa3bSJed Brown 
2413*0a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Point(DM coarse, DM fine, PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
2414*0a96aa3bSJed Brown {
2415*0a96aa3bSJed Brown   MPI_Comm          comm;
2416*0a96aa3bSJed Brown   PetscMPIInt       rank, size;
2417*0a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
2418*0a96aa3bSJed Brown   p4est_t           *p4estC, *p4estF;
2419*0a96aa3bSJed Brown   PetscInt          numClosureIndices;
2420*0a96aa3bSJed Brown   PetscInt          numClosurePointsC, numClosurePointsF;
2421*0a96aa3bSJed Brown   PetscSFNode       *closurePointsC, *closurePointsF;
2422*0a96aa3bSJed Brown   p4est_quadrant_t  *coverQuads = NULL;
2423*0a96aa3bSJed Brown   p4est_quadrant_t  **treeQuads;
2424*0a96aa3bSJed Brown   PetscInt          *treeQuadCounts;
2425*0a96aa3bSJed Brown   MPI_Datatype      nodeType;
2426*0a96aa3bSJed Brown   MPI_Datatype      nodeClosureType;
2427*0a96aa3bSJed Brown   MPI_Op            sfNodeReduce;
2428*0a96aa3bSJed Brown   p4est_topidx_t    fltF, lltF, t;
2429*0a96aa3bSJed Brown   DM                plexC, plexF;
2430*0a96aa3bSJed Brown   PetscInt          pStartF, pEndF, pStartC, pEndC;
2431*0a96aa3bSJed Brown   PetscBool         saveInCoarse = PETSC_FALSE;
2432*0a96aa3bSJed Brown   PetscBool         saveInFine   = PETSC_FALSE;
2433*0a96aa3bSJed Brown   PetscBool         formCids     = (childIds != NULL) ? PETSC_TRUE : PETSC_FALSE;
2434*0a96aa3bSJed Brown   PetscInt          *cids        = NULL;
2435*0a96aa3bSJed Brown   PetscErrorCode    ierr;
2436*0a96aa3bSJed Brown 
2437*0a96aa3bSJed Brown   PetscFunctionBegin;
2438*0a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
2439*0a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
2440*0a96aa3bSJed Brown   p4estC   = pforestC->forest;
2441*0a96aa3bSJed Brown   p4estF   = pforestF->forest;
2442*0a96aa3bSJed Brown   if (pforestC->topo != pforestF->topo) SETERRQ(PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
2443*0a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
2444*0a96aa3bSJed Brown   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
2445*0a96aa3bSJed Brown   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
2446*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(fine,&plexF);CHKERRQ(ierr);
2447*0a96aa3bSJed Brown   ierr = DMPlexGetChart(plexF,&pStartF,&pEndF);CHKERRQ(ierr);
2448*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(coarse,&plexC);CHKERRQ(ierr);
2449*0a96aa3bSJed Brown   ierr = DMPlexGetChart(plexC,&pStartC,&pEndC);CHKERRQ(ierr);
2450*0a96aa3bSJed Brown   { /* check if the results have been cached */
2451*0a96aa3bSJed Brown     DM adaptCoarse, adaptFine;
2452*0a96aa3bSJed Brown 
2453*0a96aa3bSJed Brown     ierr = DMForestGetAdaptivityForest(coarse,&adaptCoarse);CHKERRQ(ierr);
2454*0a96aa3bSJed Brown     ierr = DMForestGetAdaptivityForest(fine,&adaptFine);CHKERRQ(ierr);
2455*0a96aa3bSJed Brown     if (adaptCoarse && adaptCoarse->data == fine->data) { /* coarse is adapted from fine */
2456*0a96aa3bSJed Brown       if (pforestC->pointSelfToAdaptSF) {
2457*0a96aa3bSJed Brown         ierr = PetscObjectReference((PetscObject)(pforestC->pointSelfToAdaptSF));CHKERRQ(ierr);
2458*0a96aa3bSJed Brown         *sf  = pforestC->pointSelfToAdaptSF;
2459*0a96aa3bSJed Brown         if (childIds) {
2460*0a96aa3bSJed Brown           ierr      = PetscMalloc1(pEndF-pStartF,&cids);CHKERRQ(ierr);
2461*0a96aa3bSJed Brown           ierr      = PetscArraycpy(cids,pforestC->pointSelfToAdaptCids,pEndF-pStartF);CHKERRQ(ierr);
2462*0a96aa3bSJed Brown           *childIds = cids;
2463*0a96aa3bSJed Brown         }
2464*0a96aa3bSJed Brown         PetscFunctionReturn(0);
2465*0a96aa3bSJed Brown       } else {
2466*0a96aa3bSJed Brown         saveInCoarse = PETSC_TRUE;
2467*0a96aa3bSJed Brown         formCids     = PETSC_TRUE;
2468*0a96aa3bSJed Brown       }
2469*0a96aa3bSJed Brown     } else if (adaptFine && adaptFine->data == coarse->data) { /* fine is adapted from coarse */
2470*0a96aa3bSJed Brown       if (pforestF->pointAdaptToSelfSF) {
2471*0a96aa3bSJed Brown         ierr = PetscObjectReference((PetscObject)(pforestF->pointAdaptToSelfSF));CHKERRQ(ierr);
2472*0a96aa3bSJed Brown         *sf  = pforestF->pointAdaptToSelfSF;
2473*0a96aa3bSJed Brown         if (childIds) {
2474*0a96aa3bSJed Brown           ierr      = PetscMalloc1(pEndF-pStartF,&cids);CHKERRQ(ierr);
2475*0a96aa3bSJed Brown           ierr      = PetscArraycpy(cids,pforestF->pointAdaptToSelfCids,pEndF-pStartF);CHKERRQ(ierr);
2476*0a96aa3bSJed Brown           *childIds = cids;
2477*0a96aa3bSJed Brown         }
2478*0a96aa3bSJed Brown         PetscFunctionReturn(0);
2479*0a96aa3bSJed Brown       } else {
2480*0a96aa3bSJed Brown         saveInFine = PETSC_TRUE;
2481*0a96aa3bSJed Brown         formCids   = PETSC_TRUE;
2482*0a96aa3bSJed Brown       }
2483*0a96aa3bSJed Brown     }
2484*0a96aa3bSJed Brown   }
2485*0a96aa3bSJed Brown 
2486*0a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
2487*0a96aa3bSJed Brown   numClosureIndices = P4EST_INSUL;
2488*0a96aa3bSJed Brown   /* create the datatype */
2489*0a96aa3bSJed Brown   ierr = MPI_Type_contiguous(2,MPIU_INT,&nodeType);CHKERRMPI(ierr);
2490*0a96aa3bSJed Brown   ierr = MPI_Type_commit(&nodeType);CHKERRMPI(ierr);
2491*0a96aa3bSJed Brown   ierr = MPI_Op_create(DMPforestMaxSFNode,PETSC_FALSE,&sfNodeReduce);CHKERRMPI(ierr);
2492*0a96aa3bSJed Brown   ierr = MPI_Type_contiguous(numClosureIndices*2,MPIU_INT,&nodeClosureType);CHKERRMPI(ierr);
2493*0a96aa3bSJed Brown   ierr = MPI_Type_commit(&nodeClosureType);CHKERRMPI(ierr);
2494*0a96aa3bSJed Brown   /* everything has to go through cells: for each cell, create a list of the sfnodes in its closure */
2495*0a96aa3bSJed Brown   /* get lists of closure point SF nodes for every cell */
2496*0a96aa3bSJed Brown   ierr = DMPforestGetCellSFNodes(coarse,numClosureIndices,&numClosurePointsC,&closurePointsC,PETSC_TRUE);CHKERRQ(ierr);
2497*0a96aa3bSJed Brown   ierr = DMPforestGetCellSFNodes(fine  ,numClosureIndices,&numClosurePointsF,&closurePointsF,PETSC_FALSE);CHKERRQ(ierr);
2498*0a96aa3bSJed Brown   /* create pointers for tree lists */
2499*0a96aa3bSJed Brown   fltF = p4estF->first_local_tree;
2500*0a96aa3bSJed Brown   lltF = p4estF->last_local_tree;
2501*0a96aa3bSJed Brown   ierr = PetscCalloc2(lltF + 1  - fltF, &treeQuads, lltF + 1 - fltF, &treeQuadCounts);CHKERRQ(ierr);
2502*0a96aa3bSJed Brown   /* if the partitions don't match, ship the coarse to cover the fine */
2503*0a96aa3bSJed Brown   if (size > 1) {
2504*0a96aa3bSJed Brown     PetscInt p;
2505*0a96aa3bSJed Brown 
2506*0a96aa3bSJed Brown     for (p = 0; p < size; p++) {
2507*0a96aa3bSJed Brown       int equal;
2508*0a96aa3bSJed Brown 
2509*0a96aa3bSJed Brown       PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal_piggy,(&p4estC->global_first_position[p],&p4estF->global_first_position[p]));
2510*0a96aa3bSJed Brown       if (!equal) break;
2511*0a96aa3bSJed Brown     }
2512*0a96aa3bSJed Brown     if (p < size) { /* non-matching distribution: send the coarse to cover the fine */
2513*0a96aa3bSJed Brown       PetscInt         cStartC, cEndC;
2514*0a96aa3bSJed Brown       PetscSF          coveringSF;
2515*0a96aa3bSJed Brown       PetscInt         nleaves;
2516*0a96aa3bSJed Brown       PetscInt         count;
2517*0a96aa3bSJed Brown       PetscSFNode      *newClosurePointsC;
2518*0a96aa3bSJed Brown       p4est_quadrant_t *coverQuadsSend;
2519*0a96aa3bSJed Brown       p4est_topidx_t   fltC = p4estC->first_local_tree;
2520*0a96aa3bSJed Brown       p4est_topidx_t   lltC = p4estC->last_local_tree;
2521*0a96aa3bSJed Brown       p4est_topidx_t   t;
2522*0a96aa3bSJed Brown       PetscMPIInt      blockSizes[4]   = {P4EST_DIM,2,1,1};
2523*0a96aa3bSJed Brown       MPI_Aint         blockOffsets[4] = {offsetof(p4est_quadrant_t,x),
2524*0a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,level),
2525*0a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,pad16),
2526*0a96aa3bSJed Brown                                           offsetof(p4est_quadrant_t,p)};
2527*0a96aa3bSJed Brown       MPI_Datatype     blockTypes[4] = {MPI_INT32_T,MPI_INT8_T,MPI_INT16_T,MPI_INT32_T/* p.which_tree */};
2528*0a96aa3bSJed Brown       MPI_Datatype     quadStruct,quadType;
2529*0a96aa3bSJed Brown 
2530*0a96aa3bSJed Brown       ierr  = DMPlexGetSimplexOrBoxCells(plexC,0,&cStartC,&cEndC);CHKERRQ(ierr);
2531*0a96aa3bSJed Brown       ierr  = DMPforestGetCellCoveringSF(comm,p4estC,p4estF,pforestC->cLocalStart,pforestC->cLocalEnd,&coveringSF);CHKERRQ(ierr);
2532*0a96aa3bSJed Brown       ierr  = PetscSFGetGraph(coveringSF,NULL,&nleaves,NULL,NULL);CHKERRQ(ierr);
2533*0a96aa3bSJed Brown       ierr  = PetscMalloc1(numClosureIndices*nleaves,&newClosurePointsC);CHKERRQ(ierr);
2534*0a96aa3bSJed Brown       ierr  = PetscMalloc1(nleaves,&coverQuads);CHKERRQ(ierr);
2535*0a96aa3bSJed Brown       ierr  = PetscMalloc1(cEndC-cStartC,&coverQuadsSend);CHKERRQ(ierr);
2536*0a96aa3bSJed Brown       count = 0;
2537*0a96aa3bSJed Brown       for (t = fltC; t <= lltC; t++) { /* unfortunately, we need to pack a send array, since quads are not stored packed in p4est */
2538*0a96aa3bSJed Brown         p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
2539*0a96aa3bSJed Brown         PetscInt     q;
2540*0a96aa3bSJed Brown 
2541*0a96aa3bSJed Brown         ierr = PetscMemcpy(&coverQuadsSend[count],tree->quadrants.array,tree->quadrants.elem_count * sizeof(p4est_quadrant_t));CHKERRQ(ierr);
2542*0a96aa3bSJed Brown         for (q = 0; (size_t) q < tree->quadrants.elem_count; q++) coverQuadsSend[count+q].p.which_tree = t;
2543*0a96aa3bSJed Brown         count += tree->quadrants.elem_count;
2544*0a96aa3bSJed Brown       }
2545*0a96aa3bSJed Brown       /* p is of a union type p4est_quadrant_data, but only the p.which_tree field is active at this time. So, we
2546*0a96aa3bSJed Brown          have a simple blockTypes[] to use. Note that quadStruct does not count potential padding in array of
2547*0a96aa3bSJed Brown          p4est_quadrant_t. We have to call MPI_Type_create_resized() to change upper-bound of quadStruct.
2548*0a96aa3bSJed Brown        */
2549*0a96aa3bSJed Brown       ierr           = MPI_Type_create_struct(4,blockSizes,blockOffsets,blockTypes,&quadStruct);CHKERRMPI(ierr);
2550*0a96aa3bSJed Brown       ierr           = MPI_Type_create_resized(quadStruct,0,sizeof(p4est_quadrant_t),&quadType);CHKERRMPI(ierr);
2551*0a96aa3bSJed Brown       ierr           = MPI_Type_commit(&quadType);CHKERRMPI(ierr);
2552*0a96aa3bSJed Brown       ierr           = PetscSFBcastBegin(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE);CHKERRQ(ierr);
2553*0a96aa3bSJed Brown       ierr           = PetscSFBcastBegin(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE);CHKERRQ(ierr);
2554*0a96aa3bSJed Brown       ierr           = PetscSFBcastEnd(coveringSF,nodeClosureType,closurePointsC,newClosurePointsC,MPI_REPLACE);CHKERRQ(ierr);
2555*0a96aa3bSJed Brown       ierr           = PetscSFBcastEnd(coveringSF,quadType,coverQuadsSend,coverQuads,MPI_REPLACE);CHKERRQ(ierr);
2556*0a96aa3bSJed Brown       ierr           = MPI_Type_free(&quadStruct);CHKERRMPI(ierr);
2557*0a96aa3bSJed Brown       ierr           = MPI_Type_free(&quadType);CHKERRMPI(ierr);
2558*0a96aa3bSJed Brown       ierr           = PetscFree(coverQuadsSend);CHKERRQ(ierr);
2559*0a96aa3bSJed Brown       ierr           = PetscFree(closurePointsC);CHKERRQ(ierr);
2560*0a96aa3bSJed Brown       ierr           = PetscSFDestroy(&coveringSF);CHKERRQ(ierr);
2561*0a96aa3bSJed Brown       closurePointsC = newClosurePointsC;
2562*0a96aa3bSJed Brown 
2563*0a96aa3bSJed Brown       /* assign tree quads based on locations in coverQuads */
2564*0a96aa3bSJed Brown       {
2565*0a96aa3bSJed Brown         PetscInt q;
2566*0a96aa3bSJed Brown         for (q = 0; q < nleaves; q++) {
2567*0a96aa3bSJed Brown           p4est_locidx_t t = coverQuads[q].p.which_tree;
2568*0a96aa3bSJed Brown           if (!treeQuadCounts[t-fltF]++) treeQuads[t-fltF] = &coverQuads[q];
2569*0a96aa3bSJed Brown         }
2570*0a96aa3bSJed Brown       }
2571*0a96aa3bSJed Brown     }
2572*0a96aa3bSJed Brown   }
2573*0a96aa3bSJed Brown   if (!coverQuads) { /* matching partitions: assign tree quads based on locations in p4est native arrays */
2574*0a96aa3bSJed Brown     for (t = fltF; t <= lltF; t++) {
2575*0a96aa3bSJed Brown       p4est_tree_t *tree = &(((p4est_tree_t*) p4estC->trees->array)[t]);
2576*0a96aa3bSJed Brown 
2577*0a96aa3bSJed Brown       treeQuadCounts[t - fltF] = tree->quadrants.elem_count;
2578*0a96aa3bSJed Brown       treeQuads[t - fltF]      = (p4est_quadrant_t*) tree->quadrants.array;
2579*0a96aa3bSJed Brown     }
2580*0a96aa3bSJed Brown   }
2581*0a96aa3bSJed Brown 
2582*0a96aa3bSJed Brown   {
2583*0a96aa3bSJed Brown     PetscInt    p;
2584*0a96aa3bSJed Brown     PetscInt    cLocalStartF;
2585*0a96aa3bSJed Brown     PetscSF     pointSF;
2586*0a96aa3bSJed Brown     PetscSFNode *roots;
2587*0a96aa3bSJed Brown     PetscInt    *rootType;
2588*0a96aa3bSJed Brown     DM          refTree = NULL;
2589*0a96aa3bSJed Brown     DMLabel     canonical;
2590*0a96aa3bSJed Brown     PetscInt    *childClosures[P4EST_CHILDREN] = {NULL};
2591*0a96aa3bSJed Brown     PetscInt    *rootClosure                   = NULL;
2592*0a96aa3bSJed Brown     PetscInt    coarseOffset;
2593*0a96aa3bSJed Brown     PetscInt    numCoarseQuads;
2594*0a96aa3bSJed Brown 
2595*0a96aa3bSJed Brown     ierr = PetscMalloc1(pEndF-pStartF,&roots);CHKERRQ(ierr);
2596*0a96aa3bSJed Brown     ierr = PetscMalloc1(pEndF-pStartF,&rootType);CHKERRQ(ierr);
2597*0a96aa3bSJed Brown     ierr = DMGetPointSF(fine,&pointSF);CHKERRQ(ierr);
2598*0a96aa3bSJed Brown     for (p = pStartF; p < pEndF; p++) {
2599*0a96aa3bSJed Brown       roots[p-pStartF].rank  = -1;
2600*0a96aa3bSJed Brown       roots[p-pStartF].index = -1;
2601*0a96aa3bSJed Brown       rootType[p-pStartF]    = -1;
2602*0a96aa3bSJed Brown     }
2603*0a96aa3bSJed Brown     if (formCids) {
2604*0a96aa3bSJed Brown       PetscInt child;
2605*0a96aa3bSJed Brown 
2606*0a96aa3bSJed Brown       ierr = PetscMalloc1(pEndF-pStartF,&cids);CHKERRQ(ierr);
2607*0a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) cids[p - pStartF] = -2;
2608*0a96aa3bSJed Brown       ierr = DMPlexGetReferenceTree(plexF,&refTree);CHKERRQ(ierr);
2609*0a96aa3bSJed Brown       ierr = DMPlexGetTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure);CHKERRQ(ierr);
2610*0a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) { /* get the closures of the child cells in the reference tree */
2611*0a96aa3bSJed Brown         ierr = DMPlexGetTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]);CHKERRQ(ierr);
2612*0a96aa3bSJed Brown       }
2613*0a96aa3bSJed Brown       ierr = DMGetLabel(refTree,"canonical",&canonical);CHKERRQ(ierr);
2614*0a96aa3bSJed Brown     }
2615*0a96aa3bSJed Brown     cLocalStartF = pforestF->cLocalStart;
2616*0a96aa3bSJed Brown     for (t = fltF, coarseOffset = 0, numCoarseQuads = 0; t <= lltF; t++, coarseOffset += numCoarseQuads) {
2617*0a96aa3bSJed Brown       p4est_tree_t     *tree        = &(((p4est_tree_t*) p4estF->trees->array)[t]);
2618*0a96aa3bSJed Brown       PetscInt         numFineQuads = tree->quadrants.elem_count;
2619*0a96aa3bSJed Brown       p4est_quadrant_t *coarseQuads = treeQuads[t - fltF];
2620*0a96aa3bSJed Brown       p4est_quadrant_t *fineQuads   = (p4est_quadrant_t*) tree->quadrants.array;
2621*0a96aa3bSJed Brown       PetscInt         i, coarseCount = 0;
2622*0a96aa3bSJed Brown       PetscInt         offset = tree->quadrants_offset;
2623*0a96aa3bSJed Brown       sc_array_t       coarseQuadsArray;
2624*0a96aa3bSJed Brown 
2625*0a96aa3bSJed Brown       numCoarseQuads = treeQuadCounts[t - fltF];
2626*0a96aa3bSJed Brown       PetscStackCallP4est(sc_array_init_data,(&coarseQuadsArray,coarseQuads,sizeof(p4est_quadrant_t),(size_t) numCoarseQuads));
2627*0a96aa3bSJed Brown       for (i = 0; i < numFineQuads; i++) {
2628*0a96aa3bSJed Brown         PetscInt         c     = i + offset;
2629*0a96aa3bSJed Brown         p4est_quadrant_t *quad = &fineQuads[i];
2630*0a96aa3bSJed Brown         p4est_quadrant_t *quadCoarse = NULL;
2631*0a96aa3bSJed Brown         ssize_t          disjoint = -1;
2632*0a96aa3bSJed Brown 
2633*0a96aa3bSJed Brown         while (disjoint < 0 && coarseCount < numCoarseQuads) {
2634*0a96aa3bSJed Brown           quadCoarse = &coarseQuads[coarseCount];
2635*0a96aa3bSJed Brown           PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
2636*0a96aa3bSJed Brown           if (disjoint < 0) coarseCount++;
2637*0a96aa3bSJed Brown         }
2638*0a96aa3bSJed Brown         if (disjoint != 0) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"did not find overlapping coarse quad");
2639*0a96aa3bSJed Brown         if (quadCoarse->level > quad->level || (quadCoarse->level == quad->level && !transferIdent)) { /* the "coarse" mesh is finer than the fine mesh at the point: continue */
2640*0a96aa3bSJed Brown           if (transferIdent) { /* find corners */
2641*0a96aa3bSJed Brown             PetscInt j = 0;
2642*0a96aa3bSJed Brown 
2643*0a96aa3bSJed Brown             do {
2644*0a96aa3bSJed Brown               if (j < P4EST_CHILDREN) {
2645*0a96aa3bSJed Brown                 p4est_quadrant_t cornerQuad;
2646*0a96aa3bSJed Brown                 int              equal;
2647*0a96aa3bSJed Brown 
2648*0a96aa3bSJed Brown                 PetscStackCallP4est(p4est_quadrant_corner_descendant,(quad,&cornerQuad,j,quadCoarse->level));
2649*0a96aa3bSJed Brown                 PetscStackCallP4estReturn(equal,p4est_quadrant_is_equal,(&cornerQuad,quadCoarse));
2650*0a96aa3bSJed Brown                 if (equal) {
2651*0a96aa3bSJed Brown                   PetscInt    petscJ = P4estVertToPetscVert[j];
2652*0a96aa3bSJed Brown                   PetscInt    p      = closurePointsF[numClosureIndices * c + (P4EST_INSUL - P4EST_CHILDREN) + petscJ].index;
2653*0a96aa3bSJed Brown                   PetscSFNode q      = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + (P4EST_INSUL - P4EST_CHILDREN) + petscJ];
2654*0a96aa3bSJed Brown 
2655*0a96aa3bSJed Brown                   roots[p-pStartF]    = q;
2656*0a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
2657*0a96aa3bSJed Brown                   cids[p-pStartF]     = -1;
2658*0a96aa3bSJed Brown                   j++;
2659*0a96aa3bSJed Brown                 }
2660*0a96aa3bSJed Brown               }
2661*0a96aa3bSJed Brown               coarseCount++;
2662*0a96aa3bSJed Brown               disjoint = 1;
2663*0a96aa3bSJed Brown               if (coarseCount < numCoarseQuads) {
2664*0a96aa3bSJed Brown                 quadCoarse = &coarseQuads[coarseCount];
2665*0a96aa3bSJed Brown                 PetscStackCallP4estReturn(disjoint,p4est_quadrant_disjoint,(quadCoarse,quad));
2666*0a96aa3bSJed Brown               }
2667*0a96aa3bSJed Brown             } while (!disjoint);
2668*0a96aa3bSJed Brown           }
2669*0a96aa3bSJed Brown           continue;
2670*0a96aa3bSJed Brown         }
2671*0a96aa3bSJed Brown         if (quadCoarse->level == quad->level) { /* same quad present in coarse and fine mesh */
2672*0a96aa3bSJed Brown           PetscInt j;
2673*0a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
2674*0a96aa3bSJed Brown             PetscInt p = closurePointsF[numClosureIndices * c + j].index;
2675*0a96aa3bSJed Brown 
2676*0a96aa3bSJed Brown             roots[p-pStartF]    = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + j];
2677*0a96aa3bSJed Brown             rootType[p-pStartF] = PETSC_MAX_INT; /* unconditionally accept */
2678*0a96aa3bSJed Brown             cids[p-pStartF]     = -1;
2679*0a96aa3bSJed Brown           }
2680*0a96aa3bSJed Brown         } else {
2681*0a96aa3bSJed Brown           PetscInt levelDiff = quad->level - quadCoarse->level;
2682*0a96aa3bSJed Brown           PetscInt proposedCids[P4EST_INSUL] = {0};
2683*0a96aa3bSJed Brown 
2684*0a96aa3bSJed Brown           if (formCids) {
2685*0a96aa3bSJed Brown             PetscInt cl;
2686*0a96aa3bSJed Brown             PetscInt *pointClosure = NULL;
2687*0a96aa3bSJed Brown             int      cid;
2688*0a96aa3bSJed Brown 
2689*0a96aa3bSJed Brown             if (levelDiff > 1) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_USER,"Recursive child ids not implemented");
2690*0a96aa3bSJed Brown             PetscStackCallP4estReturn(cid,p4est_quadrant_child_id,(quad));
2691*0a96aa3bSJed Brown             ierr = DMPlexGetTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure);CHKERRQ(ierr);
2692*0a96aa3bSJed Brown             for (cl = 0; cl < P4EST_INSUL; cl++) {
2693*0a96aa3bSJed Brown               PetscInt p      = pointClosure[2 * cl];
2694*0a96aa3bSJed Brown               PetscInt point  = childClosures[cid][2 * cl];
2695*0a96aa3bSJed Brown               PetscInt ornt   = childClosures[cid][2 * cl + 1];
2696*0a96aa3bSJed Brown               PetscInt newcid = -1;
2697*0a96aa3bSJed Brown               DMPolytopeType ct;
2698*0a96aa3bSJed Brown 
2699*0a96aa3bSJed Brown               if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
2700*0a96aa3bSJed Brown               ierr = DMPlexGetCellType(refTree, point, &ct);CHKERRQ(ierr);
2701*0a96aa3bSJed Brown               ornt = DMPolytopeConvertNewOrientation_Internal(ct, ornt);
2702*0a96aa3bSJed Brown               if (!cl) {
2703*0a96aa3bSJed Brown                 newcid = cid + 1;
2704*0a96aa3bSJed Brown               } else {
2705*0a96aa3bSJed Brown                 PetscInt rcl, parent, parentOrnt = 0;
2706*0a96aa3bSJed Brown 
2707*0a96aa3bSJed Brown                 ierr = DMPlexGetTreeParent(refTree,point,&parent,NULL);CHKERRQ(ierr);
2708*0a96aa3bSJed Brown                 if (parent == point) {
2709*0a96aa3bSJed Brown                   newcid = -1;
2710*0a96aa3bSJed Brown                 } else if (!parent) { /* in the root */
2711*0a96aa3bSJed Brown                   newcid = point;
2712*0a96aa3bSJed Brown                 } else {
2713*0a96aa3bSJed Brown                   DMPolytopeType rct = DM_POLYTOPE_UNKNOWN;
2714*0a96aa3bSJed Brown 
2715*0a96aa3bSJed Brown                   for (rcl = 1; rcl < P4EST_INSUL; rcl++) {
2716*0a96aa3bSJed Brown                     if (rootClosure[2 * rcl] == parent) {
2717*0a96aa3bSJed Brown                       ierr = DMPlexGetCellType(refTree, parent, &rct);CHKERRQ(ierr);
2718*0a96aa3bSJed Brown                       parentOrnt = DMPolytopeConvertNewOrientation_Internal(rct, rootClosure[2 * rcl + 1]);
2719*0a96aa3bSJed Brown                       break;
2720*0a96aa3bSJed Brown                     }
2721*0a96aa3bSJed Brown                   }
2722*0a96aa3bSJed Brown                   if (rcl >= P4EST_INSUL) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Couldn't find parent in root closure");
2723*0a96aa3bSJed Brown                   ierr = DMPlexReferenceTreeGetChildSymmetry(refTree,parent,parentOrnt,ornt,point,DMPolytopeConvertNewOrientation_Internal(rct, pointClosure[2 * rcl + 1]),NULL,&newcid);CHKERRQ(ierr);
2724*0a96aa3bSJed Brown                 }
2725*0a96aa3bSJed Brown               }
2726*0a96aa3bSJed Brown               if (newcid >= 0) {
2727*0a96aa3bSJed Brown 
2728*0a96aa3bSJed Brown                 if (canonical) {
2729*0a96aa3bSJed Brown                   ierr = DMLabelGetValue(canonical,newcid,&newcid);CHKERRQ(ierr);
2730*0a96aa3bSJed Brown                 }
2731*0a96aa3bSJed Brown                 proposedCids[cl] = newcid;
2732*0a96aa3bSJed Brown               }
2733*0a96aa3bSJed Brown             }
2734*0a96aa3bSJed Brown             ierr = DMPlexRestoreTransitiveClosure(plexF,c + cLocalStartF,PETSC_TRUE,NULL,&pointClosure);CHKERRQ(ierr);
2735*0a96aa3bSJed Brown           }
2736*0a96aa3bSJed Brown           p4est_qcoord_t coarseBound[2][P4EST_DIM] = {{quadCoarse->x,quadCoarse->y,
2737*0a96aa3bSJed Brown #if defined(P4_TO_P8)
2738*0a96aa3bSJed Brown                                                        quadCoarse->z
2739*0a96aa3bSJed Brown #endif
2740*0a96aa3bSJed Brown                                                       },{0}};
2741*0a96aa3bSJed Brown           p4est_qcoord_t fineBound[2][P4EST_DIM] = {{quad->x,quad->y,
2742*0a96aa3bSJed Brown #if defined(P4_TO_P8)
2743*0a96aa3bSJed Brown                                                      quad->z
2744*0a96aa3bSJed Brown #endif
2745*0a96aa3bSJed Brown                                                     },{0}};
2746*0a96aa3bSJed Brown           PetscInt       j;
2747*0a96aa3bSJed Brown           for (j = 0; j < P4EST_DIM; j++) { /* get the coordinates of cell boundaries in each direction */
2748*0a96aa3bSJed Brown             coarseBound[1][j] = coarseBound[0][j] + P4EST_QUADRANT_LEN(quadCoarse->level);
2749*0a96aa3bSJed Brown             fineBound[1][j]   = fineBound[0][j]   + P4EST_QUADRANT_LEN(quad->level);
2750*0a96aa3bSJed Brown           }
2751*0a96aa3bSJed Brown           for (j = 0; j < numClosureIndices; j++) {
2752*0a96aa3bSJed Brown             PetscInt    l, p;
2753*0a96aa3bSJed Brown             PetscSFNode q;
2754*0a96aa3bSJed Brown 
2755*0a96aa3bSJed Brown             p = closurePointsF[numClosureIndices * c + j].index;
2756*0a96aa3bSJed Brown             if (rootType[p-pStartF] == PETSC_MAX_INT) continue;
2757*0a96aa3bSJed Brown             if (j == 0) { /* volume: ancestor is volume */
2758*0a96aa3bSJed Brown               l = 0;
2759*0a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES) { /* facet */
2760*0a96aa3bSJed Brown               PetscInt face = PetscFaceToP4estFace[j - 1];
2761*0a96aa3bSJed Brown               PetscInt direction = face / 2;
2762*0a96aa3bSJed Brown               PetscInt coarseFace = -1;
2763*0a96aa3bSJed Brown 
2764*0a96aa3bSJed Brown               if (coarseBound[face % 2][direction] == fineBound[face % 2][direction]) {
2765*0a96aa3bSJed Brown                 coarseFace = face;
2766*0a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
2767*0a96aa3bSJed Brown               } else {
2768*0a96aa3bSJed Brown                 l = 0;
2769*0a96aa3bSJed Brown               }
2770*0a96aa3bSJed Brown #if defined(P4_TO_P8)
2771*0a96aa3bSJed Brown             } else if (j < 1 + P4EST_FACES + P8EST_EDGES) {
2772*0a96aa3bSJed Brown               PetscInt  edge       = PetscEdgeToP4estEdge[j - (1 + P4EST_FACES)];
2773*0a96aa3bSJed Brown               PetscInt  direction  = edge / 4;
2774*0a96aa3bSJed Brown               PetscInt  mod        = edge % 4;
2775*0a96aa3bSJed Brown               PetscInt  coarseEdge = -1, coarseFace = -1;
2776*0a96aa3bSJed Brown               PetscInt  minDir     = PetscMin((direction + 1) % 3,(direction + 2) % 3);
2777*0a96aa3bSJed Brown               PetscInt  maxDir     = PetscMax((direction + 1) % 3,(direction + 2) % 3);
2778*0a96aa3bSJed Brown               PetscBool dirTest[2];
2779*0a96aa3bSJed Brown 
2780*0a96aa3bSJed Brown               dirTest[0] = (PetscBool) (coarseBound[mod % 2][minDir] == fineBound[mod % 2][minDir]);
2781*0a96aa3bSJed Brown               dirTest[1] = (PetscBool) (coarseBound[mod / 2][maxDir] == fineBound[mod / 2][maxDir]);
2782*0a96aa3bSJed Brown 
2783*0a96aa3bSJed Brown               if (dirTest[0] && dirTest[1]) { /* fine edge falls on coarse edge */
2784*0a96aa3bSJed Brown                 coarseEdge = edge;
2785*0a96aa3bSJed Brown                 l          = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
2786*0a96aa3bSJed Brown               } else if (dirTest[0]) { /* fine edge falls on a coarse face in the minDir direction */
2787*0a96aa3bSJed Brown                 coarseFace = 2 * minDir + (mod % 2);
2788*0a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
2789*0a96aa3bSJed Brown               } else if (dirTest[1]) { /* fine edge falls on a coarse face in the maxDir direction */
2790*0a96aa3bSJed Brown                 coarseFace = 2 * maxDir + (mod / 2);
2791*0a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
2792*0a96aa3bSJed Brown               } else {
2793*0a96aa3bSJed Brown                 l = 0;
2794*0a96aa3bSJed Brown               }
2795*0a96aa3bSJed Brown #endif
2796*0a96aa3bSJed Brown             } else {
2797*0a96aa3bSJed Brown               PetscInt  vertex = PetscVertToP4estVert[P4EST_CHILDREN - (P4EST_INSUL - j)];
2798*0a96aa3bSJed Brown               PetscBool dirTest[P4EST_DIM];
2799*0a96aa3bSJed Brown               PetscInt  m;
2800*0a96aa3bSJed Brown               PetscInt  numMatch     = 0;
2801*0a96aa3bSJed Brown               PetscInt  coarseVertex = -1, coarseFace = -1;
2802*0a96aa3bSJed Brown #if defined(P4_TO_P8)
2803*0a96aa3bSJed Brown               PetscInt coarseEdge = -1;
2804*0a96aa3bSJed Brown #endif
2805*0a96aa3bSJed Brown 
2806*0a96aa3bSJed Brown               for (m = 0; m < P4EST_DIM; m++) {
2807*0a96aa3bSJed Brown                 dirTest[m] = (PetscBool) (coarseBound[(vertex >> m) & 1][m] == fineBound[(vertex >> m) & 1][m]);
2808*0a96aa3bSJed Brown                 if (dirTest[m]) numMatch++;
2809*0a96aa3bSJed Brown               }
2810*0a96aa3bSJed Brown               if (numMatch == P4EST_DIM) { /* vertex on vertex */
2811*0a96aa3bSJed Brown                 coarseVertex = vertex;
2812*0a96aa3bSJed Brown                 l            = P4EST_INSUL - (P4EST_CHILDREN - P4estVertToPetscVert[coarseVertex]);
2813*0a96aa3bSJed Brown               } else if (numMatch == 1) { /* vertex on face */
2814*0a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
2815*0a96aa3bSJed Brown                   if (dirTest[m]) {
2816*0a96aa3bSJed Brown                     coarseFace = 2 * m + ((vertex >> m) & 1);
2817*0a96aa3bSJed Brown                     break;
2818*0a96aa3bSJed Brown                   }
2819*0a96aa3bSJed Brown                 }
2820*0a96aa3bSJed Brown                 l = 1 + P4estFaceToPetscFace[coarseFace];
2821*0a96aa3bSJed Brown #if defined(P4_TO_P8)
2822*0a96aa3bSJed Brown               } else if (numMatch == 2) { /* vertex on edge */
2823*0a96aa3bSJed Brown                 for (m = 0; m < P4EST_DIM; m++) {
2824*0a96aa3bSJed Brown                   if (!dirTest[m]) {
2825*0a96aa3bSJed Brown                     PetscInt otherDir1 = (m + 1) % 3;
2826*0a96aa3bSJed Brown                     PetscInt otherDir2 = (m + 2) % 3;
2827*0a96aa3bSJed Brown                     PetscInt minDir    = PetscMin(otherDir1,otherDir2);
2828*0a96aa3bSJed Brown                     PetscInt maxDir    = PetscMax(otherDir1,otherDir2);
2829*0a96aa3bSJed Brown 
2830*0a96aa3bSJed Brown                     coarseEdge = m * 4 + 2 * ((vertex >> maxDir) & 1) + ((vertex >> minDir) & 1);
2831*0a96aa3bSJed Brown                     break;
2832*0a96aa3bSJed Brown                   }
2833*0a96aa3bSJed Brown                 }
2834*0a96aa3bSJed Brown                 l = 1 + P4EST_FACES + P4estEdgeToPetscEdge[coarseEdge];
2835*0a96aa3bSJed Brown #endif
2836*0a96aa3bSJed Brown               } else { /* volume */
2837*0a96aa3bSJed Brown                 l = 0;
2838*0a96aa3bSJed Brown               }
2839*0a96aa3bSJed Brown             }
2840*0a96aa3bSJed Brown             q = closurePointsC[numClosureIndices * (coarseCount + coarseOffset) + l];
2841*0a96aa3bSJed Brown             if (l > rootType[p-pStartF]) {
2842*0a96aa3bSJed Brown               if (l >= P4EST_INSUL - P4EST_CHILDREN) { /* vertex on vertex: unconditional acceptance */
2843*0a96aa3bSJed Brown                 if (transferIdent) {
2844*0a96aa3bSJed Brown                   roots[p-pStartF] = q;
2845*0a96aa3bSJed Brown                   rootType[p-pStartF] = PETSC_MAX_INT;
2846*0a96aa3bSJed Brown                   if (formCids) cids[p-pStartF] = -1;
2847*0a96aa3bSJed Brown                 }
2848*0a96aa3bSJed Brown               } else {
2849*0a96aa3bSJed Brown                 PetscInt k, thisp = p, limit;
2850*0a96aa3bSJed Brown 
2851*0a96aa3bSJed Brown                 roots[p-pStartF] = q;
2852*0a96aa3bSJed Brown                 rootType[p-pStartF] = l;
2853*0a96aa3bSJed Brown                 if (formCids) cids[p - pStartF] = proposedCids[j];
2854*0a96aa3bSJed Brown                 limit = transferIdent ? levelDiff : (levelDiff - 1);
2855*0a96aa3bSJed Brown                 for (k = 0; k < limit; k++) {
2856*0a96aa3bSJed Brown                   PetscInt parent;
2857*0a96aa3bSJed Brown 
2858*0a96aa3bSJed Brown                   ierr = DMPlexGetTreeParent(plexF,thisp,&parent,NULL);CHKERRQ(ierr);
2859*0a96aa3bSJed Brown                   if (parent == thisp) break;
2860*0a96aa3bSJed Brown 
2861*0a96aa3bSJed Brown                   roots[parent-pStartF] = q;
2862*0a96aa3bSJed Brown                   rootType[parent-pStartF] = PETSC_MAX_INT;
2863*0a96aa3bSJed Brown                   if (formCids) cids[parent-pStartF] = -1;
2864*0a96aa3bSJed Brown                   thisp = parent;
2865*0a96aa3bSJed Brown                 }
2866*0a96aa3bSJed Brown               }
2867*0a96aa3bSJed Brown             }
2868*0a96aa3bSJed Brown           }
2869*0a96aa3bSJed Brown         }
2870*0a96aa3bSJed Brown       }
2871*0a96aa3bSJed Brown     }
2872*0a96aa3bSJed Brown 
2873*0a96aa3bSJed 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 */
2874*0a96aa3bSJed Brown     if (size > 1) {
2875*0a96aa3bSJed Brown       PetscInt *rootTypeCopy, p;
2876*0a96aa3bSJed Brown 
2877*0a96aa3bSJed Brown       ierr = PetscMalloc1(pEndF-pStartF,&rootTypeCopy);CHKERRQ(ierr);
2878*0a96aa3bSJed Brown       ierr = PetscArraycpy(rootTypeCopy,rootType,pEndF-pStartF);CHKERRQ(ierr);
2879*0a96aa3bSJed Brown       ierr = PetscSFReduceBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX);CHKERRQ(ierr);
2880*0a96aa3bSJed Brown       ierr = PetscSFReduceEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPIU_MAX);CHKERRQ(ierr);
2881*0a96aa3bSJed Brown       ierr = PetscSFBcastBegin(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE);CHKERRQ(ierr);
2882*0a96aa3bSJed Brown       ierr = PetscSFBcastEnd(pointSF,MPIU_INT,rootTypeCopy,rootTypeCopy,MPI_REPLACE);CHKERRQ(ierr);
2883*0a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
2884*0a96aa3bSJed 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 */
2885*0a96aa3bSJed Brown           roots[p-pStartF].rank  = -1;
2886*0a96aa3bSJed Brown           roots[p-pStartF].index = -1;
2887*0a96aa3bSJed Brown         }
2888*0a96aa3bSJed Brown         if (formCids && rootTypeCopy[p-pStartF] == PETSC_MAX_INT) {
2889*0a96aa3bSJed Brown           cids[p-pStartF] = -1; /* we have found an antecedent that is the same: no child id */
2890*0a96aa3bSJed Brown         }
2891*0a96aa3bSJed Brown       }
2892*0a96aa3bSJed Brown       ierr = PetscFree(rootTypeCopy);CHKERRQ(ierr);
2893*0a96aa3bSJed Brown       ierr = PetscSFReduceBegin(pointSF,nodeType,roots,roots,sfNodeReduce);CHKERRQ(ierr);
2894*0a96aa3bSJed Brown       ierr = PetscSFReduceEnd(pointSF,nodeType,roots,roots,sfNodeReduce);CHKERRQ(ierr);
2895*0a96aa3bSJed Brown       ierr = PetscSFBcastBegin(pointSF,nodeType,roots,roots,MPI_REPLACE);CHKERRQ(ierr);
2896*0a96aa3bSJed Brown       ierr = PetscSFBcastEnd(pointSF,nodeType,roots,roots,MPI_REPLACE);CHKERRQ(ierr);
2897*0a96aa3bSJed Brown     }
2898*0a96aa3bSJed Brown     ierr = PetscFree(rootType);CHKERRQ(ierr);
2899*0a96aa3bSJed Brown 
2900*0a96aa3bSJed Brown     {
2901*0a96aa3bSJed Brown       PetscInt    numRoots;
2902*0a96aa3bSJed Brown       PetscInt    numLeaves;
2903*0a96aa3bSJed Brown       PetscInt    *leaves;
2904*0a96aa3bSJed Brown       PetscSFNode *iremote;
2905*0a96aa3bSJed Brown       /* count leaves */
2906*0a96aa3bSJed Brown 
2907*0a96aa3bSJed Brown       numRoots = pEndC - pStartC;
2908*0a96aa3bSJed Brown 
2909*0a96aa3bSJed Brown       numLeaves = 0;
2910*0a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
2911*0a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) numLeaves++;
2912*0a96aa3bSJed Brown       }
2913*0a96aa3bSJed Brown       ierr      = PetscMalloc1(numLeaves,&leaves);CHKERRQ(ierr);
2914*0a96aa3bSJed Brown       ierr      = PetscMalloc1(numLeaves,&iremote);CHKERRQ(ierr);
2915*0a96aa3bSJed Brown       numLeaves = 0;
2916*0a96aa3bSJed Brown       for (p = pStartF; p < pEndF; p++) {
2917*0a96aa3bSJed Brown         if (roots[p-pStartF].index >= 0) {
2918*0a96aa3bSJed Brown           leaves[numLeaves]  = p-pStartF;
2919*0a96aa3bSJed Brown           iremote[numLeaves] = roots[p-pStartF];
2920*0a96aa3bSJed Brown           numLeaves++;
2921*0a96aa3bSJed Brown         }
2922*0a96aa3bSJed Brown       }
2923*0a96aa3bSJed Brown       ierr = PetscFree(roots);CHKERRQ(ierr);
2924*0a96aa3bSJed Brown       ierr = PetscSFCreate(comm,sf);CHKERRQ(ierr);
2925*0a96aa3bSJed Brown       if (numLeaves == (pEndF-pStartF)) {
2926*0a96aa3bSJed Brown         ierr = PetscFree(leaves);CHKERRQ(ierr);
2927*0a96aa3bSJed Brown         ierr = PetscSFSetGraph(*sf,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
2928*0a96aa3bSJed Brown       } else {
2929*0a96aa3bSJed Brown         ierr = PetscSFSetGraph(*sf,numRoots,numLeaves,leaves,PETSC_OWN_POINTER,iremote,PETSC_OWN_POINTER);CHKERRQ(ierr);
2930*0a96aa3bSJed Brown       }
2931*0a96aa3bSJed Brown     }
2932*0a96aa3bSJed Brown     if (formCids) {
2933*0a96aa3bSJed Brown       PetscSF  pointSF;
2934*0a96aa3bSJed Brown       PetscInt child;
2935*0a96aa3bSJed Brown 
2936*0a96aa3bSJed Brown       ierr = DMPlexGetReferenceTree(plexF,&refTree);CHKERRQ(ierr);
2937*0a96aa3bSJed Brown       ierr = DMGetPointSF(plexF,&pointSF);CHKERRQ(ierr);
2938*0a96aa3bSJed Brown       ierr = PetscSFReduceBegin(pointSF,MPIU_INT,cids,cids,MPIU_MAX);CHKERRQ(ierr);
2939*0a96aa3bSJed Brown       ierr = PetscSFReduceEnd(pointSF,MPIU_INT,cids,cids,MPIU_MAX);CHKERRQ(ierr);
2940*0a96aa3bSJed Brown       if (childIds) *childIds = cids;
2941*0a96aa3bSJed Brown       for (child = 0; child < P4EST_CHILDREN; child++) {
2942*0a96aa3bSJed Brown         ierr = DMPlexRestoreTransitiveClosure(refTree,child+1,PETSC_TRUE,NULL,&childClosures[child]);CHKERRQ(ierr);
2943*0a96aa3bSJed Brown       }
2944*0a96aa3bSJed Brown       ierr = DMPlexRestoreTransitiveClosure(refTree,0,PETSC_TRUE,NULL,&rootClosure);CHKERRQ(ierr);
2945*0a96aa3bSJed Brown     }
2946*0a96aa3bSJed Brown   }
2947*0a96aa3bSJed Brown   if (saveInCoarse) { /* cache results */
2948*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)*sf);CHKERRQ(ierr);
2949*0a96aa3bSJed Brown     pforestC->pointSelfToAdaptSF = *sf;
2950*0a96aa3bSJed Brown     if (!childIds) {
2951*0a96aa3bSJed Brown       pforestC->pointSelfToAdaptCids = cids;
2952*0a96aa3bSJed Brown     } else {
2953*0a96aa3bSJed Brown       ierr = PetscMalloc1(pEndF-pStartF,&pforestC->pointSelfToAdaptCids);CHKERRQ(ierr);
2954*0a96aa3bSJed Brown       ierr = PetscArraycpy(pforestC->pointSelfToAdaptCids,cids,pEndF-pStartF);CHKERRQ(ierr);
2955*0a96aa3bSJed Brown     }
2956*0a96aa3bSJed Brown   } else if (saveInFine) {
2957*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)*sf);CHKERRQ(ierr);
2958*0a96aa3bSJed Brown     pforestF->pointAdaptToSelfSF = *sf;
2959*0a96aa3bSJed Brown     if (!childIds) {
2960*0a96aa3bSJed Brown       pforestF->pointAdaptToSelfCids = cids;
2961*0a96aa3bSJed Brown     } else {
2962*0a96aa3bSJed Brown       ierr = PetscMalloc1(pEndF-pStartF,&pforestF->pointAdaptToSelfCids);CHKERRQ(ierr);
2963*0a96aa3bSJed Brown       ierr = PetscArraycpy(pforestF->pointAdaptToSelfCids,cids,pEndF-pStartF);CHKERRQ(ierr);
2964*0a96aa3bSJed Brown     }
2965*0a96aa3bSJed Brown   }
2966*0a96aa3bSJed Brown   ierr = PetscFree2(treeQuads,treeQuadCounts);CHKERRQ(ierr);
2967*0a96aa3bSJed Brown   ierr = PetscFree(coverQuads);CHKERRQ(ierr);
2968*0a96aa3bSJed Brown   ierr = PetscFree(closurePointsC);CHKERRQ(ierr);
2969*0a96aa3bSJed Brown   ierr = PetscFree(closurePointsF);CHKERRQ(ierr);
2970*0a96aa3bSJed Brown   ierr = MPI_Type_free(&nodeClosureType);CHKERRMPI(ierr);
2971*0a96aa3bSJed Brown   ierr = MPI_Op_free(&sfNodeReduce);CHKERRMPI(ierr);
2972*0a96aa3bSJed Brown   ierr = MPI_Type_free(&nodeType);CHKERRMPI(ierr);
2973*0a96aa3bSJed Brown   PetscFunctionReturn(0);
2974*0a96aa3bSJed Brown }
2975*0a96aa3bSJed Brown 
2976*0a96aa3bSJed Brown /* children are sf leaves of parents */
2977*0a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF_Internal(DM coarse, DM fine, const PetscInt dofPerDim[], PetscSF *sf, PetscBool transferIdent, PetscInt *childIds[])
2978*0a96aa3bSJed Brown {
2979*0a96aa3bSJed Brown   MPI_Comm          comm;
2980*0a96aa3bSJed Brown   PetscMPIInt       rank, size;
2981*0a96aa3bSJed Brown   DM_Forest_pforest *pforestC, *pforestF;
2982*0a96aa3bSJed Brown   PetscInt          numClosureIndices;
2983*0a96aa3bSJed Brown   DM                plexC, plexF;
2984*0a96aa3bSJed Brown   PetscInt          pStartC, pEndC, pStartF, pEndF;
2985*0a96aa3bSJed Brown   PetscSF           pointTransferSF;
2986*0a96aa3bSJed Brown   PetscBool         allOnes = PETSC_TRUE;
2987*0a96aa3bSJed Brown   PetscErrorCode    ierr;
2988*0a96aa3bSJed Brown 
2989*0a96aa3bSJed Brown   PetscFunctionBegin;
2990*0a96aa3bSJed Brown   pforestC = (DM_Forest_pforest*) ((DM_Forest*) coarse->data)->data;
2991*0a96aa3bSJed Brown   pforestF = (DM_Forest_pforest*) ((DM_Forest*) fine->data)->data;
2992*0a96aa3bSJed Brown   if (pforestC->topo != pforestF->topo) SETERRQ(PetscObjectComm((PetscObject)coarse),PETSC_ERR_ARG_INCOMP,"DM's must have the same base DM");
2993*0a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)coarse);
2994*0a96aa3bSJed Brown   ierr = MPI_Comm_rank(comm,&rank);CHKERRMPI(ierr);
2995*0a96aa3bSJed Brown   ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
2996*0a96aa3bSJed Brown 
2997*0a96aa3bSJed Brown   /* count the number of closure points that have dofs and create a list */
2998*0a96aa3bSJed Brown   numClosureIndices = 0;
2999*0a96aa3bSJed Brown   if (dofPerDim[P4EST_DIM]     > 0) numClosureIndices += 1;
3000*0a96aa3bSJed Brown   if (dofPerDim[P4EST_DIM - 1] > 0) numClosureIndices += P4EST_FACES;
3001*0a96aa3bSJed Brown #if defined(P4_TO_P8)
3002*0a96aa3bSJed Brown   if (dofPerDim[P4EST_DIM - 2] > 0) numClosureIndices += P8EST_EDGES;
3003*0a96aa3bSJed Brown #endif
3004*0a96aa3bSJed Brown   if (dofPerDim[0]             > 0) numClosureIndices += P4EST_CHILDREN;
3005*0a96aa3bSJed Brown   {
3006*0a96aa3bSJed Brown     PetscInt i;
3007*0a96aa3bSJed Brown     for (i = 0; i <= P4EST_DIM; i++) {
3008*0a96aa3bSJed Brown       if (dofPerDim[i] != 1) {
3009*0a96aa3bSJed Brown         allOnes = PETSC_FALSE;
3010*0a96aa3bSJed Brown         break;
3011*0a96aa3bSJed Brown       }
3012*0a96aa3bSJed Brown     }
3013*0a96aa3bSJed Brown   }
3014*0a96aa3bSJed Brown   ierr = DMPforestGetTransferSF_Point(coarse,fine,&pointTransferSF,transferIdent,childIds);CHKERRQ(ierr);
3015*0a96aa3bSJed Brown   if (allOnes) {
3016*0a96aa3bSJed Brown     *sf = pointTransferSF;
3017*0a96aa3bSJed Brown     PetscFunctionReturn(0);
3018*0a96aa3bSJed Brown   }
3019*0a96aa3bSJed Brown 
3020*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(fine,&plexF);CHKERRQ(ierr);
3021*0a96aa3bSJed Brown   ierr = DMPlexGetChart(plexF,&pStartF,&pEndF);CHKERRQ(ierr);
3022*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(coarse,&plexC);CHKERRQ(ierr);
3023*0a96aa3bSJed Brown   ierr = DMPlexGetChart(plexC,&pStartC,&pEndC);CHKERRQ(ierr);
3024*0a96aa3bSJed Brown   {
3025*0a96aa3bSJed Brown     PetscInt          numRoots;
3026*0a96aa3bSJed Brown     PetscInt          numLeaves;
3027*0a96aa3bSJed Brown     const PetscInt    *leaves;
3028*0a96aa3bSJed Brown     const PetscSFNode *iremote;
3029*0a96aa3bSJed Brown     PetscInt          d;
3030*0a96aa3bSJed Brown     PetscSection      leafSection, rootSection;
3031*0a96aa3bSJed Brown     /* count leaves */
3032*0a96aa3bSJed Brown 
3033*0a96aa3bSJed Brown     ierr = PetscSFGetGraph(pointTransferSF,&numRoots,&numLeaves,&leaves,&iremote);CHKERRQ(ierr);
3034*0a96aa3bSJed Brown     ierr = PetscSectionCreate(PETSC_COMM_SELF,&rootSection);CHKERRQ(ierr);
3035*0a96aa3bSJed Brown     ierr = PetscSectionCreate(PETSC_COMM_SELF,&leafSection);CHKERRQ(ierr);
3036*0a96aa3bSJed Brown     ierr = PetscSectionSetChart(rootSection,pStartC,pEndC);CHKERRQ(ierr);
3037*0a96aa3bSJed Brown     ierr = PetscSectionSetChart(leafSection,pStartF,pEndF);CHKERRQ(ierr);
3038*0a96aa3bSJed Brown 
3039*0a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
3040*0a96aa3bSJed Brown       PetscInt startC, endC, e;
3041*0a96aa3bSJed Brown 
3042*0a96aa3bSJed Brown       ierr = DMPlexGetSimplexOrBoxCells(plexC,P4EST_DIM-d,&startC,&endC);CHKERRQ(ierr);
3043*0a96aa3bSJed Brown       for (e = startC; e < endC; e++) {
3044*0a96aa3bSJed Brown         ierr = PetscSectionSetDof(rootSection,e,dofPerDim[d]);CHKERRQ(ierr);
3045*0a96aa3bSJed Brown       }
3046*0a96aa3bSJed Brown     }
3047*0a96aa3bSJed Brown 
3048*0a96aa3bSJed Brown     for (d = 0; d <= P4EST_DIM; d++) {
3049*0a96aa3bSJed Brown       PetscInt startF, endF, e;
3050*0a96aa3bSJed Brown 
3051*0a96aa3bSJed Brown       ierr = DMPlexGetSimplexOrBoxCells(plexF,P4EST_DIM-d,&startF,&endF);CHKERRQ(ierr);
3052*0a96aa3bSJed Brown       for (e = startF; e < endF; e++) {
3053*0a96aa3bSJed Brown         ierr = PetscSectionSetDof(leafSection,e,dofPerDim[d]);CHKERRQ(ierr);
3054*0a96aa3bSJed Brown       }
3055*0a96aa3bSJed Brown     }
3056*0a96aa3bSJed Brown 
3057*0a96aa3bSJed Brown     ierr = PetscSectionSetUp(rootSection);CHKERRQ(ierr);
3058*0a96aa3bSJed Brown     ierr = PetscSectionSetUp(leafSection);CHKERRQ(ierr);
3059*0a96aa3bSJed Brown     {
3060*0a96aa3bSJed Brown       PetscInt    nroots, nleaves;
3061*0a96aa3bSJed Brown       PetscInt    *mine, i, p;
3062*0a96aa3bSJed Brown       PetscInt    *offsets, *offsetsRoot;
3063*0a96aa3bSJed Brown       PetscSFNode *remote;
3064*0a96aa3bSJed Brown 
3065*0a96aa3bSJed Brown       ierr = PetscMalloc1(pEndF-pStartF,&offsets);CHKERRQ(ierr);
3066*0a96aa3bSJed Brown       ierr = PetscMalloc1(pEndC-pStartC,&offsetsRoot);CHKERRQ(ierr);
3067*0a96aa3bSJed Brown       for (p = pStartC; p < pEndC; p++) {
3068*0a96aa3bSJed Brown         ierr = PetscSectionGetOffset(rootSection,p,&offsetsRoot[p-pStartC]);CHKERRQ(ierr);
3069*0a96aa3bSJed Brown       }
3070*0a96aa3bSJed Brown       ierr    = PetscSFBcastBegin(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE);CHKERRQ(ierr);
3071*0a96aa3bSJed Brown       ierr    = PetscSFBcastEnd(pointTransferSF,MPIU_INT,offsetsRoot,offsets,MPI_REPLACE);CHKERRQ(ierr);
3072*0a96aa3bSJed Brown       ierr    = PetscSectionGetStorageSize(rootSection,&nroots);CHKERRQ(ierr);
3073*0a96aa3bSJed Brown       nleaves = 0;
3074*0a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
3075*0a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
3076*0a96aa3bSJed Brown         PetscInt dof;
3077*0a96aa3bSJed Brown 
3078*0a96aa3bSJed Brown         ierr     = PetscSectionGetDof(leafSection,leaf,&dof);CHKERRQ(ierr);
3079*0a96aa3bSJed Brown         nleaves += dof;
3080*0a96aa3bSJed Brown       }
3081*0a96aa3bSJed Brown       ierr    = PetscMalloc1(nleaves,&mine);CHKERRQ(ierr);
3082*0a96aa3bSJed Brown       ierr    = PetscMalloc1(nleaves,&remote);CHKERRQ(ierr);
3083*0a96aa3bSJed Brown       nleaves = 0;
3084*0a96aa3bSJed Brown       for (i = 0; i < numLeaves; i++) {
3085*0a96aa3bSJed Brown         PetscInt leaf = leaves ? leaves[i] : i;
3086*0a96aa3bSJed Brown         PetscInt dof;
3087*0a96aa3bSJed Brown         PetscInt off, j;
3088*0a96aa3bSJed Brown 
3089*0a96aa3bSJed Brown         ierr = PetscSectionGetDof(leafSection,leaf,&dof);CHKERRQ(ierr);
3090*0a96aa3bSJed Brown         ierr = PetscSectionGetOffset(leafSection,leaf,&off);CHKERRQ(ierr);
3091*0a96aa3bSJed Brown         for (j = 0; j < dof; j++) {
3092*0a96aa3bSJed Brown           remote[nleaves].rank  = iremote[i].rank;
3093*0a96aa3bSJed Brown           remote[nleaves].index = offsets[leaf] + j;
3094*0a96aa3bSJed Brown           mine[nleaves++]       = off + j;
3095*0a96aa3bSJed Brown         }
3096*0a96aa3bSJed Brown       }
3097*0a96aa3bSJed Brown       ierr = PetscFree(offsetsRoot);CHKERRQ(ierr);
3098*0a96aa3bSJed Brown       ierr = PetscFree(offsets);CHKERRQ(ierr);
3099*0a96aa3bSJed Brown       ierr = PetscSFCreate(comm,sf);CHKERRQ(ierr);
3100*0a96aa3bSJed Brown       ierr = PetscSFSetGraph(*sf,nroots,nleaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER);CHKERRQ(ierr);
3101*0a96aa3bSJed Brown     }
3102*0a96aa3bSJed Brown     ierr = PetscSectionDestroy(&leafSection);CHKERRQ(ierr);
3103*0a96aa3bSJed Brown     ierr = PetscSectionDestroy(&rootSection);CHKERRQ(ierr);
3104*0a96aa3bSJed Brown     ierr = PetscSFDestroy(&pointTransferSF);CHKERRQ(ierr);
3105*0a96aa3bSJed Brown   }
3106*0a96aa3bSJed Brown   PetscFunctionReturn(0);
3107*0a96aa3bSJed Brown }
3108*0a96aa3bSJed Brown 
3109*0a96aa3bSJed Brown static PetscErrorCode DMPforestGetTransferSF(DM dmA, DM dmB, const PetscInt dofPerDim[], PetscSF *sfAtoB, PetscSF *sfBtoA)
3110*0a96aa3bSJed Brown {
3111*0a96aa3bSJed Brown   DM             adaptA, adaptB;
3112*0a96aa3bSJed Brown   DMAdaptFlag    purpose;
3113*0a96aa3bSJed Brown   PetscErrorCode ierr;
3114*0a96aa3bSJed Brown 
3115*0a96aa3bSJed Brown   PetscFunctionBegin;
3116*0a96aa3bSJed Brown   ierr = DMForestGetAdaptivityForest(dmA,&adaptA);CHKERRQ(ierr);
3117*0a96aa3bSJed Brown   ierr = DMForestGetAdaptivityForest(dmB,&adaptB);CHKERRQ(ierr);
3118*0a96aa3bSJed Brown   /* it is more efficient when the coarser mesh is the first argument: reorder if we know one is coarser than the other */
3119*0a96aa3bSJed Brown   if (adaptA && adaptA->data == dmB->data) { /* dmA was adapted from dmB */
3120*0a96aa3bSJed Brown     ierr = DMForestGetAdaptivityPurpose(dmA,&purpose);CHKERRQ(ierr);
3121*0a96aa3bSJed Brown     if (purpose == DM_ADAPT_REFINE) {
3122*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB);CHKERRQ(ierr);
3123*0a96aa3bSJed Brown       PetscFunctionReturn(0);
3124*0a96aa3bSJed Brown     }
3125*0a96aa3bSJed Brown   } else if (adaptB && adaptB->data == dmA->data) { /* dmB was adapted from dmA */
3126*0a96aa3bSJed Brown     ierr = DMForestGetAdaptivityPurpose(dmB,&purpose);CHKERRQ(ierr);
3127*0a96aa3bSJed Brown     if (purpose == DM_ADAPT_COARSEN) {
3128*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF(dmB, dmA, dofPerDim, sfBtoA, sfAtoB);CHKERRQ(ierr);
3129*0a96aa3bSJed Brown       PetscFunctionReturn(0);
3130*0a96aa3bSJed Brown     }
3131*0a96aa3bSJed Brown   }
3132*0a96aa3bSJed Brown   if (sfAtoB) {
3133*0a96aa3bSJed Brown     ierr = DMPforestGetTransferSF_Internal(dmA,dmB,dofPerDim,sfAtoB,PETSC_TRUE,NULL);CHKERRQ(ierr);
3134*0a96aa3bSJed Brown   }
3135*0a96aa3bSJed Brown   if (sfBtoA) {
3136*0a96aa3bSJed Brown     ierr = DMPforestGetTransferSF_Internal(dmB,dmA,dofPerDim,sfBtoA,(PetscBool) (sfAtoB == NULL),NULL);CHKERRQ(ierr);
3137*0a96aa3bSJed Brown   }
3138*0a96aa3bSJed Brown   PetscFunctionReturn(0);
3139*0a96aa3bSJed Brown }
3140*0a96aa3bSJed Brown 
3141*0a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsInitialize(DM dm, DM plex)
3142*0a96aa3bSJed Brown {
3143*0a96aa3bSJed Brown   DM_Forest         *forest  = (DM_Forest*) dm->data;
3144*0a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data;
3145*0a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, cStart, cEnd, fStart, fEnd, eStart, eEnd, vStart, vEnd;
3146*0a96aa3bSJed Brown   PetscInt          cStartBase, cEndBase, fStartBase, fEndBase, vStartBase, vEndBase, eStartBase, eEndBase;
3147*0a96aa3bSJed Brown   PetscInt          pStart, pEnd, pStartBase, pEndBase, p;
3148*0a96aa3bSJed Brown   DM                base;
3149*0a96aa3bSJed Brown   PetscInt          *star     = NULL, starSize;
3150*0a96aa3bSJed Brown   DMLabelLink       next      = dm->labels;
3151*0a96aa3bSJed Brown   PetscInt          guess     = 0;
3152*0a96aa3bSJed Brown   p4est_topidx_t    num_trees = pforest->topo->conn->num_trees;
3153*0a96aa3bSJed Brown   PetscErrorCode    ierr;
3154*0a96aa3bSJed Brown 
3155*0a96aa3bSJed Brown   PetscFunctionBegin;
3156*0a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
3157*0a96aa3bSJed Brown   cLocalStart              = pforest->cLocalStart;
3158*0a96aa3bSJed Brown   cLocalEnd                = pforest->cLocalEnd;
3159*0a96aa3bSJed Brown   ierr                     = DMForestGetBaseDM(dm,&base);CHKERRQ(ierr);
3160*0a96aa3bSJed Brown   if (!base) {
3161*0a96aa3bSJed Brown     if (pforest->ghostName) { /* insert a label to make the boundaries, with stratum values denoting which face of the element touches the boundary */
3162*0a96aa3bSJed Brown       p4est_connectivity_t *conn  = pforest->topo->conn;
3163*0a96aa3bSJed Brown       p4est_t              *p4est = pforest->forest;
3164*0a96aa3bSJed Brown       p4est_tree_t         *trees = (p4est_tree_t*) p4est->trees->array;
3165*0a96aa3bSJed Brown       p4est_topidx_t       t, flt = p4est->first_local_tree;
3166*0a96aa3bSJed Brown       p4est_topidx_t       llt = pforest->forest->last_local_tree;
3167*0a96aa3bSJed Brown       DMLabel              ghostLabel;
3168*0a96aa3bSJed Brown       PetscInt             c;
3169*0a96aa3bSJed Brown 
3170*0a96aa3bSJed Brown       ierr = DMCreateLabel(plex,pforest->ghostName);CHKERRQ(ierr);
3171*0a96aa3bSJed Brown       ierr = DMGetLabel(plex,pforest->ghostName,&ghostLabel);CHKERRQ(ierr);
3172*0a96aa3bSJed Brown       for (c = cLocalStart, t = flt; t <= llt; t++) {
3173*0a96aa3bSJed Brown         p4est_tree_t     *tree    = &trees[t];
3174*0a96aa3bSJed Brown         p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
3175*0a96aa3bSJed Brown         PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
3176*0a96aa3bSJed Brown         PetscInt         q;
3177*0a96aa3bSJed Brown 
3178*0a96aa3bSJed Brown         for (q = 0; q < numQuads; q++, c++) {
3179*0a96aa3bSJed Brown           p4est_quadrant_t *quad = &quads[q];
3180*0a96aa3bSJed Brown           PetscInt         f;
3181*0a96aa3bSJed Brown 
3182*0a96aa3bSJed Brown           for (f = 0; f < P4EST_FACES; f++) {
3183*0a96aa3bSJed Brown             p4est_quadrant_t neigh;
3184*0a96aa3bSJed Brown             int              isOutside;
3185*0a96aa3bSJed Brown 
3186*0a96aa3bSJed Brown             PetscStackCallP4est(p4est_quadrant_face_neighbor,(quad,f,&neigh));
3187*0a96aa3bSJed Brown             PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&neigh));
3188*0a96aa3bSJed Brown             if (isOutside) {
3189*0a96aa3bSJed Brown               p4est_topidx_t nt;
3190*0a96aa3bSJed Brown               PetscInt       nf;
3191*0a96aa3bSJed Brown 
3192*0a96aa3bSJed Brown               nt = conn->tree_to_tree[t * P4EST_FACES + f];
3193*0a96aa3bSJed Brown               nf = (PetscInt) conn->tree_to_face[t * P4EST_FACES + f];
3194*0a96aa3bSJed Brown               nf = nf % P4EST_FACES;
3195*0a96aa3bSJed Brown               if (nt == t && nf == f) {
3196*0a96aa3bSJed Brown                 PetscInt       plexF = P4estFaceToPetscFace[f];
3197*0a96aa3bSJed Brown                 const PetscInt *cone;
3198*0a96aa3bSJed Brown 
3199*0a96aa3bSJed Brown                 ierr = DMPlexGetCone(plex,c,&cone);CHKERRQ(ierr);
3200*0a96aa3bSJed Brown                 ierr = DMLabelSetValue(ghostLabel,cone[plexF],plexF+1);CHKERRQ(ierr);
3201*0a96aa3bSJed Brown               }
3202*0a96aa3bSJed Brown             }
3203*0a96aa3bSJed Brown           }
3204*0a96aa3bSJed Brown         }
3205*0a96aa3bSJed Brown       }
3206*0a96aa3bSJed Brown     }
3207*0a96aa3bSJed Brown     PetscFunctionReturn(0);
3208*0a96aa3bSJed Brown   }
3209*0a96aa3bSJed Brown   ierr     = DMPlexGetSimplexOrBoxCells(base,0,&cStartBase,&cEndBase);CHKERRQ(ierr);
3210*0a96aa3bSJed Brown   ierr     = DMPlexGetSimplexOrBoxCells(base,1,&fStartBase,&fEndBase);CHKERRQ(ierr);
3211*0a96aa3bSJed Brown   ierr     = DMPlexGetSimplexOrBoxCells(base,P4EST_DIM-1,&eStartBase,&eEndBase);CHKERRQ(ierr);
3212*0a96aa3bSJed Brown   ierr     = DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase);CHKERRQ(ierr);
3213*0a96aa3bSJed Brown 
3214*0a96aa3bSJed Brown   ierr = DMPlexGetSimplexOrBoxCells(plex,0,&cStart,&cEnd);CHKERRQ(ierr);
3215*0a96aa3bSJed Brown   ierr = DMPlexGetSimplexOrBoxCells(plex,1,&fStart,&fEnd);CHKERRQ(ierr);
3216*0a96aa3bSJed Brown   ierr = DMPlexGetSimplexOrBoxCells(plex,P4EST_DIM-1,&eStart,&eEnd);CHKERRQ(ierr);
3217*0a96aa3bSJed Brown   ierr = DMPlexGetDepthStratum(plex,0,&vStart,&vEnd);CHKERRQ(ierr);
3218*0a96aa3bSJed Brown 
3219*0a96aa3bSJed Brown   ierr = DMPlexGetChart(plex,&pStart,&pEnd);CHKERRQ(ierr);
3220*0a96aa3bSJed Brown   ierr = DMPlexGetChart(base,&pStartBase,&pEndBase);CHKERRQ(ierr);
3221*0a96aa3bSJed Brown   /* go through the mesh: use star to find a quadrant that borders a point.  Use the closure to determine the
3222*0a96aa3bSJed Brown    * orientation of the quadrant relative to that point.  Use that to relate the point to the numbering in the base
3223*0a96aa3bSJed Brown    * mesh, and extract a label value (since the base mesh is redundantly distributed, can be found locally). */
3224*0a96aa3bSJed Brown   while (next) {
3225*0a96aa3bSJed Brown     DMLabel   baseLabel;
3226*0a96aa3bSJed Brown     DMLabel   label = next->label;
3227*0a96aa3bSJed Brown     PetscBool isDepth, isCellType, isGhost, isVTK, isSpmap;
3228*0a96aa3bSJed Brown     const char *name;
3229*0a96aa3bSJed Brown 
3230*0a96aa3bSJed Brown     ierr = PetscObjectGetName((PetscObject) label, &name);CHKERRQ(ierr);
3231*0a96aa3bSJed Brown     ierr = PetscStrcmp(name,"depth",&isDepth);CHKERRQ(ierr);
3232*0a96aa3bSJed Brown     if (isDepth) {
3233*0a96aa3bSJed Brown       next = next->next;
3234*0a96aa3bSJed Brown       continue;
3235*0a96aa3bSJed Brown     }
3236*0a96aa3bSJed Brown     ierr = PetscStrcmp(name,"celltype",&isCellType);CHKERRQ(ierr);
3237*0a96aa3bSJed Brown     if (isCellType) {
3238*0a96aa3bSJed Brown       next = next->next;
3239*0a96aa3bSJed Brown       continue;
3240*0a96aa3bSJed Brown     }
3241*0a96aa3bSJed Brown     ierr = PetscStrcmp(name,"ghost",&isGhost);CHKERRQ(ierr);
3242*0a96aa3bSJed Brown     if (isGhost) {
3243*0a96aa3bSJed Brown       next = next->next;
3244*0a96aa3bSJed Brown       continue;
3245*0a96aa3bSJed Brown     }
3246*0a96aa3bSJed Brown     ierr = PetscStrcmp(name,"vtk",&isVTK);CHKERRQ(ierr);
3247*0a96aa3bSJed Brown     if (isVTK) {
3248*0a96aa3bSJed Brown       next = next->next;
3249*0a96aa3bSJed Brown       continue;
3250*0a96aa3bSJed Brown     }
3251*0a96aa3bSJed Brown     ierr = PetscStrcmp(name,"_forest_base_subpoint_map",&isSpmap);CHKERRQ(ierr);
3252*0a96aa3bSJed Brown     if (!isSpmap) {
3253*0a96aa3bSJed Brown       ierr = DMGetLabel(base,name,&baseLabel);CHKERRQ(ierr);
3254*0a96aa3bSJed Brown       if (!baseLabel) {
3255*0a96aa3bSJed Brown         next = next->next;
3256*0a96aa3bSJed Brown         continue;
3257*0a96aa3bSJed Brown       }
3258*0a96aa3bSJed Brown       ierr = DMLabelCreateIndex(baseLabel,pStartBase,pEndBase);CHKERRQ(ierr);
3259*0a96aa3bSJed Brown     } else baseLabel = NULL;
3260*0a96aa3bSJed Brown 
3261*0a96aa3bSJed Brown     for (p = pStart; p < pEnd; p++) {
3262*0a96aa3bSJed Brown       PetscInt         s, c = -1, l;
3263*0a96aa3bSJed Brown       PetscInt         *closure = NULL, closureSize;
3264*0a96aa3bSJed Brown       p4est_quadrant_t * ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
3265*0a96aa3bSJed Brown       p4est_tree_t     *trees   = (p4est_tree_t*) pforest->forest->trees->array;
3266*0a96aa3bSJed Brown       p4est_quadrant_t * q;
3267*0a96aa3bSJed Brown       PetscInt         t, val;
3268*0a96aa3bSJed Brown       PetscBool        zerosupportpoint = PETSC_FALSE;
3269*0a96aa3bSJed Brown 
3270*0a96aa3bSJed Brown       ierr = DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
3271*0a96aa3bSJed Brown       for (s = 0; s < starSize; s++) {
3272*0a96aa3bSJed Brown         PetscInt point = star[2*s];
3273*0a96aa3bSJed Brown 
3274*0a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
3275*0a96aa3bSJed Brown           ierr = DMPlexGetTransitiveClosure(plex,point,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
3276*0a96aa3bSJed Brown           for (l = 0; l < closureSize; l++) {
3277*0a96aa3bSJed Brown             PetscInt qParent = closure[2 * l], q, pp = p, pParent = p;
3278*0a96aa3bSJed Brown             do { /* check parents of q */
3279*0a96aa3bSJed Brown               q = qParent;
3280*0a96aa3bSJed Brown               if (q == p) {
3281*0a96aa3bSJed Brown                 c = point;
3282*0a96aa3bSJed Brown                 break;
3283*0a96aa3bSJed Brown               }
3284*0a96aa3bSJed Brown               ierr = DMPlexGetTreeParent(plex,q,&qParent,NULL);CHKERRQ(ierr);
3285*0a96aa3bSJed Brown             } while (qParent != q);
3286*0a96aa3bSJed Brown             if (c != -1) break;
3287*0a96aa3bSJed Brown             ierr = DMPlexGetTreeParent(plex,pp,&pParent,NULL);CHKERRQ(ierr);
3288*0a96aa3bSJed Brown             q = closure[2 * l];
3289*0a96aa3bSJed Brown             while (pParent != pp) { /* check parents of p */
3290*0a96aa3bSJed Brown               pp = pParent;
3291*0a96aa3bSJed Brown               if (pp == q) {
3292*0a96aa3bSJed Brown                 c = point;
3293*0a96aa3bSJed Brown                 break;
3294*0a96aa3bSJed Brown               }
3295*0a96aa3bSJed Brown               ierr = DMPlexGetTreeParent(plex,pp,&pParent,NULL);CHKERRQ(ierr);
3296*0a96aa3bSJed Brown             }
3297*0a96aa3bSJed Brown             if (c != -1) break;
3298*0a96aa3bSJed Brown           }
3299*0a96aa3bSJed Brown           ierr = DMPlexRestoreTransitiveClosure(plex,point,PETSC_TRUE,NULL,&closure);CHKERRQ(ierr);
3300*0a96aa3bSJed Brown           if (l < closureSize) break;
3301*0a96aa3bSJed Brown         } else {
3302*0a96aa3bSJed Brown           PetscInt supportSize;
3303*0a96aa3bSJed Brown 
3304*0a96aa3bSJed Brown           ierr = DMPlexGetSupportSize(plex,point,&supportSize);CHKERRQ(ierr);
3305*0a96aa3bSJed Brown           zerosupportpoint = (PetscBool) (zerosupportpoint || !supportSize);
3306*0a96aa3bSJed Brown         }
3307*0a96aa3bSJed Brown       }
3308*0a96aa3bSJed Brown       if (c < 0) {
3309*0a96aa3bSJed Brown         const char* prefix;
3310*0a96aa3bSJed Brown         PetscBool   print = PETSC_FALSE;
3311*0a96aa3bSJed Brown 
3312*0a96aa3bSJed Brown         ierr = PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix);CHKERRQ(ierr);
3313*0a96aa3bSJed Brown         ierr = PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_forest_print_label_error",&print,NULL);CHKERRQ(ierr);
3314*0a96aa3bSJed Brown         if (print) {
3315*0a96aa3bSJed Brown           PetscInt i;
3316*0a96aa3bSJed Brown 
3317*0a96aa3bSJed Brown           ierr = PetscPrintf(PETSC_COMM_SELF,"[%d] Failed to find cell with point %D in its closure for label %s (starSize %D)\n",PetscGlobalRank,p,baseLabel ? ((PetscObject)baseLabel)->name : "_forest_base_subpoint_map",starSize);CHKERRQ(ierr);
3318*0a96aa3bSJed Brown           for (i = 0; i < starSize; i++) { ierr = PetscPrintf(PETSC_COMM_SELF,"  star[%D] = %D,%D\n",i,star[2*i],star[2*i+1]);CHKERRQ(ierr); }
3319*0a96aa3bSJed Brown         }
3320*0a96aa3bSJed Brown         ierr = DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star);CHKERRQ(ierr);
3321*0a96aa3bSJed Brown         if (zerosupportpoint) continue;
3322*0a96aa3bSJed Brown         else SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Failed to find cell with point %D in its closure for label %s. Rerun with -dm_forest_print_label_error for more information",p,baseLabel ? ((PetscObject) baseLabel)->name : "_forest_base_subpoint_map");
3323*0a96aa3bSJed Brown       }
3324*0a96aa3bSJed Brown       ierr = DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,NULL,&star);CHKERRQ(ierr);
3325*0a96aa3bSJed Brown 
3326*0a96aa3bSJed Brown       if (c < cLocalStart) {
3327*0a96aa3bSJed Brown         /* get from the beginning of the ghost layer */
3328*0a96aa3bSJed Brown         q = &(ghosts[c]);
3329*0a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
3330*0a96aa3bSJed Brown       } else if (c < cLocalEnd) {
3331*0a96aa3bSJed Brown         PetscInt lo = 0, hi = num_trees;
3332*0a96aa3bSJed Brown         /* get from local quadrants: have to find the right tree */
3333*0a96aa3bSJed Brown 
3334*0a96aa3bSJed Brown         c -= cLocalStart;
3335*0a96aa3bSJed Brown 
3336*0a96aa3bSJed Brown         do {
3337*0a96aa3bSJed Brown           p4est_tree_t *tree;
3338*0a96aa3bSJed Brown 
3339*0a96aa3bSJed Brown           if (guess < lo || guess >= num_trees || lo >= hi) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"failed binary search");
3340*0a96aa3bSJed Brown           tree = &trees[guess];
3341*0a96aa3bSJed Brown           if (c < tree->quadrants_offset) {
3342*0a96aa3bSJed Brown             hi = guess;
3343*0a96aa3bSJed Brown           } else if (c < tree->quadrants_offset + (PetscInt) tree->quadrants.elem_count) {
3344*0a96aa3bSJed Brown             q = &((p4est_quadrant_t *)tree->quadrants.array)[c - (PetscInt) tree->quadrants_offset];
3345*0a96aa3bSJed Brown             t = guess;
3346*0a96aa3bSJed Brown             break;
3347*0a96aa3bSJed Brown           } else {
3348*0a96aa3bSJed Brown             lo = guess + 1;
3349*0a96aa3bSJed Brown           }
3350*0a96aa3bSJed Brown           guess = lo + (hi - lo) / 2;
3351*0a96aa3bSJed Brown         } while (1);
3352*0a96aa3bSJed Brown       } else {
3353*0a96aa3bSJed Brown         /* get from the end of the ghost layer */
3354*0a96aa3bSJed Brown         c -= (cLocalEnd - cLocalStart);
3355*0a96aa3bSJed Brown 
3356*0a96aa3bSJed Brown         q = &(ghosts[c]);
3357*0a96aa3bSJed Brown         t = (PetscInt) q->p.which_tree;
3358*0a96aa3bSJed Brown       }
3359*0a96aa3bSJed Brown 
3360*0a96aa3bSJed Brown       if (l == 0) { /* cell */
3361*0a96aa3bSJed Brown         if (baseLabel) {
3362*0a96aa3bSJed Brown           ierr = DMLabelGetValue(baseLabel,t+cStartBase,&val);CHKERRQ(ierr);
3363*0a96aa3bSJed Brown         } else {
3364*0a96aa3bSJed Brown           val  = t+cStartBase;
3365*0a96aa3bSJed Brown         }
3366*0a96aa3bSJed Brown         ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3367*0a96aa3bSJed Brown       } else if (l >= 1 && l < 1 + P4EST_FACES) { /* facet */
3368*0a96aa3bSJed Brown         p4est_quadrant_t nq;
3369*0a96aa3bSJed Brown         int              isInside;
3370*0a96aa3bSJed Brown 
3371*0a96aa3bSJed Brown         l = PetscFaceToP4estFace[l - 1];
3372*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_face_neighbor,(q,l,&nq));
3373*0a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
3374*0a96aa3bSJed Brown         if (isInside) {
3375*0a96aa3bSJed Brown           /* this facet is in the interior of a tree, so it inherits the label of the tree */
3376*0a96aa3bSJed Brown           if (baseLabel) {
3377*0a96aa3bSJed Brown             ierr = DMLabelGetValue(baseLabel,t+cStartBase,&val);CHKERRQ(ierr);
3378*0a96aa3bSJed Brown           } else {
3379*0a96aa3bSJed Brown             val  = t+cStartBase;
3380*0a96aa3bSJed Brown           }
3381*0a96aa3bSJed Brown           ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3382*0a96aa3bSJed Brown         } else {
3383*0a96aa3bSJed Brown           PetscInt f = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + l];
3384*0a96aa3bSJed Brown 
3385*0a96aa3bSJed Brown           if (baseLabel) {
3386*0a96aa3bSJed Brown             ierr = DMLabelGetValue(baseLabel,f+fStartBase,&val);CHKERRQ(ierr);
3387*0a96aa3bSJed Brown           } else {
3388*0a96aa3bSJed Brown             val  = f+fStartBase;
3389*0a96aa3bSJed Brown           }
3390*0a96aa3bSJed Brown           ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3391*0a96aa3bSJed Brown         }
3392*0a96aa3bSJed Brown #if defined(P4_TO_P8)
3393*0a96aa3bSJed Brown       } else if (l >= 1 + P4EST_FACES && l < 1 + P4EST_FACES + P8EST_EDGES) { /* edge */
3394*0a96aa3bSJed Brown         p4est_quadrant_t nq;
3395*0a96aa3bSJed Brown         int              isInside;
3396*0a96aa3bSJed Brown 
3397*0a96aa3bSJed Brown         l = PetscEdgeToP4estEdge[l - (1 + P4EST_FACES)];
3398*0a96aa3bSJed Brown         PetscStackCallP4est(p8est_quadrant_edge_neighbor,(q,l,&nq));
3399*0a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
3400*0a96aa3bSJed Brown         if (isInside) {
3401*0a96aa3bSJed Brown           /* this edge is in the interior of a tree, so it inherits the label of the tree */
3402*0a96aa3bSJed Brown           if (baseLabel) {
3403*0a96aa3bSJed Brown             ierr = DMLabelGetValue(baseLabel,t+cStartBase,&val);CHKERRQ(ierr);
3404*0a96aa3bSJed Brown           } else {
3405*0a96aa3bSJed Brown             val  = t+cStartBase;
3406*0a96aa3bSJed Brown           }
3407*0a96aa3bSJed Brown           ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3408*0a96aa3bSJed Brown         } else {
3409*0a96aa3bSJed Brown           int isOutsideFace;
3410*0a96aa3bSJed Brown 
3411*0a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutsideFace,p4est_quadrant_is_outside_face,(&nq));
3412*0a96aa3bSJed Brown           if (isOutsideFace) {
3413*0a96aa3bSJed Brown             PetscInt f;
3414*0a96aa3bSJed Brown 
3415*0a96aa3bSJed Brown             if (nq.x < 0) {
3416*0a96aa3bSJed Brown               f = 0;
3417*0a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
3418*0a96aa3bSJed Brown               f = 1;
3419*0a96aa3bSJed Brown             } else if (nq.y < 0) {
3420*0a96aa3bSJed Brown               f = 2;
3421*0a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
3422*0a96aa3bSJed Brown               f = 3;
3423*0a96aa3bSJed Brown             } else if (nq.z < 0) {
3424*0a96aa3bSJed Brown               f = 4;
3425*0a96aa3bSJed Brown             } else {
3426*0a96aa3bSJed Brown               f = 5;
3427*0a96aa3bSJed Brown             }
3428*0a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
3429*0a96aa3bSJed Brown             if (baseLabel) {
3430*0a96aa3bSJed Brown               ierr = DMLabelGetValue(baseLabel,f+fStartBase,&val);CHKERRQ(ierr);
3431*0a96aa3bSJed Brown             } else {
3432*0a96aa3bSJed Brown               val  = f+fStartBase;
3433*0a96aa3bSJed Brown             }
3434*0a96aa3bSJed Brown             ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3435*0a96aa3bSJed Brown           } else { /* the quadrant edge corresponds to the tree edge */
3436*0a96aa3bSJed Brown             PetscInt e = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + l];
3437*0a96aa3bSJed Brown 
3438*0a96aa3bSJed Brown             if (baseLabel) {
3439*0a96aa3bSJed Brown               ierr = DMLabelGetValue(baseLabel,e+eStartBase,&val);CHKERRQ(ierr);
3440*0a96aa3bSJed Brown             } else {
3441*0a96aa3bSJed Brown               val  = e+eStartBase;
3442*0a96aa3bSJed Brown             }
3443*0a96aa3bSJed Brown             ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3444*0a96aa3bSJed Brown           }
3445*0a96aa3bSJed Brown         }
3446*0a96aa3bSJed Brown #endif
3447*0a96aa3bSJed Brown       } else { /* vertex */
3448*0a96aa3bSJed Brown         p4est_quadrant_t nq;
3449*0a96aa3bSJed Brown         int              isInside;
3450*0a96aa3bSJed Brown 
3451*0a96aa3bSJed Brown #if defined(P4_TO_P8)
3452*0a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES + P8EST_EDGES)];
3453*0a96aa3bSJed Brown #else
3454*0a96aa3bSJed Brown         l = PetscVertToP4estVert[l - (1 + P4EST_FACES)];
3455*0a96aa3bSJed Brown #endif
3456*0a96aa3bSJed Brown         PetscStackCallP4est(p4est_quadrant_corner_neighbor,(q,l,&nq));
3457*0a96aa3bSJed Brown         PetscStackCallP4estReturn(isInside,p4est_quadrant_is_inside_root,(&nq));
3458*0a96aa3bSJed Brown         if (isInside) {
3459*0a96aa3bSJed Brown           if (baseLabel) {
3460*0a96aa3bSJed Brown             ierr = DMLabelGetValue(baseLabel,t+cStartBase,&val);CHKERRQ(ierr);
3461*0a96aa3bSJed Brown           } else {
3462*0a96aa3bSJed Brown             val  = t+cStartBase;
3463*0a96aa3bSJed Brown           }
3464*0a96aa3bSJed Brown           ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3465*0a96aa3bSJed Brown         } else {
3466*0a96aa3bSJed Brown           int isOutside;
3467*0a96aa3bSJed Brown 
3468*0a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p4est_quadrant_is_outside_face,(&nq));
3469*0a96aa3bSJed Brown           if (isOutside) {
3470*0a96aa3bSJed Brown             PetscInt f = -1;
3471*0a96aa3bSJed Brown 
3472*0a96aa3bSJed Brown             if (nq.x < 0) {
3473*0a96aa3bSJed Brown               f = 0;
3474*0a96aa3bSJed Brown             } else if (nq.x >= P4EST_ROOT_LEN) {
3475*0a96aa3bSJed Brown               f = 1;
3476*0a96aa3bSJed Brown             } else if (nq.y < 0) {
3477*0a96aa3bSJed Brown               f = 2;
3478*0a96aa3bSJed Brown             } else if (nq.y >= P4EST_ROOT_LEN) {
3479*0a96aa3bSJed Brown               f = 3;
3480*0a96aa3bSJed Brown #if defined(P4_TO_P8)
3481*0a96aa3bSJed Brown             } else if (nq.z < 0) {
3482*0a96aa3bSJed Brown               f = 4;
3483*0a96aa3bSJed Brown             } else {
3484*0a96aa3bSJed Brown               f = 5;
3485*0a96aa3bSJed Brown #endif
3486*0a96aa3bSJed Brown             }
3487*0a96aa3bSJed Brown             f    = pforest->topo->tree_face_to_uniq[P4EST_FACES * t + f];
3488*0a96aa3bSJed Brown             if (baseLabel) {
3489*0a96aa3bSJed Brown               ierr = DMLabelGetValue(baseLabel,f+fStartBase,&val);CHKERRQ(ierr);
3490*0a96aa3bSJed Brown             } else {
3491*0a96aa3bSJed Brown               val  = f+fStartBase;
3492*0a96aa3bSJed Brown             }
3493*0a96aa3bSJed Brown             ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3494*0a96aa3bSJed Brown             continue;
3495*0a96aa3bSJed Brown           }
3496*0a96aa3bSJed Brown #if defined(P4_TO_P8)
3497*0a96aa3bSJed Brown           PetscStackCallP4estReturn(isOutside,p8est_quadrant_is_outside_edge,(&nq));
3498*0a96aa3bSJed Brown           if (isOutside) {
3499*0a96aa3bSJed Brown             /* outside edge */
3500*0a96aa3bSJed Brown             PetscInt e = -1;
3501*0a96aa3bSJed Brown 
3502*0a96aa3bSJed Brown             if (nq.x >= 0 && nq.x < P4EST_ROOT_LEN) {
3503*0a96aa3bSJed Brown               if (nq.z < 0) {
3504*0a96aa3bSJed Brown                 if (nq.y < 0) {
3505*0a96aa3bSJed Brown                   e = 0;
3506*0a96aa3bSJed Brown                 } else {
3507*0a96aa3bSJed Brown                   e = 1;
3508*0a96aa3bSJed Brown                 }
3509*0a96aa3bSJed Brown               } else {
3510*0a96aa3bSJed Brown                 if (nq.y < 0) {
3511*0a96aa3bSJed Brown                   e = 2;
3512*0a96aa3bSJed Brown                 } else {
3513*0a96aa3bSJed Brown                   e = 3;
3514*0a96aa3bSJed Brown                 }
3515*0a96aa3bSJed Brown               }
3516*0a96aa3bSJed Brown             } else if (nq.y >= 0 && nq.y < P4EST_ROOT_LEN) {
3517*0a96aa3bSJed Brown               if (nq.z < 0) {
3518*0a96aa3bSJed Brown                 if (nq.x < 0) {
3519*0a96aa3bSJed Brown                   e = 4;
3520*0a96aa3bSJed Brown                 } else {
3521*0a96aa3bSJed Brown                   e = 5;
3522*0a96aa3bSJed Brown                 }
3523*0a96aa3bSJed Brown               } else {
3524*0a96aa3bSJed Brown                 if (nq.x < 0) {
3525*0a96aa3bSJed Brown                   e = 6;
3526*0a96aa3bSJed Brown                 } else {
3527*0a96aa3bSJed Brown                   e = 7;
3528*0a96aa3bSJed Brown                 }
3529*0a96aa3bSJed Brown               }
3530*0a96aa3bSJed Brown             } else {
3531*0a96aa3bSJed Brown               if (nq.y < 0) {
3532*0a96aa3bSJed Brown                 if (nq.x < 0) {
3533*0a96aa3bSJed Brown                   e = 8;
3534*0a96aa3bSJed Brown                 } else {
3535*0a96aa3bSJed Brown                   e = 9;
3536*0a96aa3bSJed Brown                 }
3537*0a96aa3bSJed Brown               } else {
3538*0a96aa3bSJed Brown                 if (nq.x < 0) {
3539*0a96aa3bSJed Brown                   e = 10;
3540*0a96aa3bSJed Brown                 } else {
3541*0a96aa3bSJed Brown                   e = 11;
3542*0a96aa3bSJed Brown                 }
3543*0a96aa3bSJed Brown               }
3544*0a96aa3bSJed Brown             }
3545*0a96aa3bSJed Brown 
3546*0a96aa3bSJed Brown             e    = pforest->topo->conn->tree_to_edge[P8EST_EDGES * t + e];
3547*0a96aa3bSJed Brown             if (baseLabel) {
3548*0a96aa3bSJed Brown               ierr = DMLabelGetValue(baseLabel,e+eStartBase,&val);CHKERRQ(ierr);
3549*0a96aa3bSJed Brown             } else {
3550*0a96aa3bSJed Brown               val  = e+eStartBase;
3551*0a96aa3bSJed Brown             }
3552*0a96aa3bSJed Brown             ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3553*0a96aa3bSJed Brown             continue;
3554*0a96aa3bSJed Brown           }
3555*0a96aa3bSJed Brown #endif
3556*0a96aa3bSJed Brown           {
3557*0a96aa3bSJed Brown             /* outside vertex: same corner as quadrant corner */
3558*0a96aa3bSJed Brown             PetscInt v = pforest->topo->conn->tree_to_corner[P4EST_CHILDREN * t + l];
3559*0a96aa3bSJed Brown 
3560*0a96aa3bSJed Brown             if (baseLabel) {
3561*0a96aa3bSJed Brown               ierr = DMLabelGetValue(baseLabel,v+vStartBase,&val);CHKERRQ(ierr);
3562*0a96aa3bSJed Brown             } else {
3563*0a96aa3bSJed Brown               val  = v+vStartBase;
3564*0a96aa3bSJed Brown             }
3565*0a96aa3bSJed Brown             ierr = DMLabelSetValue(label,p,val);CHKERRQ(ierr);
3566*0a96aa3bSJed Brown           }
3567*0a96aa3bSJed Brown         }
3568*0a96aa3bSJed Brown       }
3569*0a96aa3bSJed Brown     }
3570*0a96aa3bSJed Brown     next = next->next;
3571*0a96aa3bSJed Brown   }
3572*0a96aa3bSJed Brown   PetscFunctionReturn(0);
3573*0a96aa3bSJed Brown }
3574*0a96aa3bSJed Brown 
3575*0a96aa3bSJed Brown static PetscErrorCode DMPforestLabelsFinalize(DM dm, DM plex)
3576*0a96aa3bSJed Brown {
3577*0a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
3578*0a96aa3bSJed Brown   DM                adapt;
3579*0a96aa3bSJed Brown   PetscErrorCode    ierr;
3580*0a96aa3bSJed Brown 
3581*0a96aa3bSJed Brown   PetscFunctionBegin;
3582*0a96aa3bSJed Brown   if (pforest->labelsFinalized) PetscFunctionReturn(0);
3583*0a96aa3bSJed Brown   pforest->labelsFinalized = PETSC_TRUE;
3584*0a96aa3bSJed Brown   ierr                     = DMForestGetAdaptivityForest(dm,&adapt);CHKERRQ(ierr);
3585*0a96aa3bSJed Brown   if (!adapt) {
3586*0a96aa3bSJed Brown     /* Initialize labels from the base dm */
3587*0a96aa3bSJed Brown     ierr = DMPforestLabelsInitialize(dm,plex);CHKERRQ(ierr);
3588*0a96aa3bSJed Brown   } else {
3589*0a96aa3bSJed Brown     PetscInt    dofPerDim[4]={1, 1, 1, 1};
3590*0a96aa3bSJed Brown     PetscSF     transferForward, transferBackward, pointSF;
3591*0a96aa3bSJed Brown     PetscInt    pStart, pEnd, pStartA, pEndA;
3592*0a96aa3bSJed Brown     PetscInt    *values, *adaptValues;
3593*0a96aa3bSJed Brown     DMLabelLink next = adapt->labels;
3594*0a96aa3bSJed Brown     DMLabel     adaptLabel;
3595*0a96aa3bSJed Brown     DM          adaptPlex;
3596*0a96aa3bSJed Brown 
3597*0a96aa3bSJed Brown     ierr = DMForestGetAdaptivityLabel(dm,&adaptLabel);CHKERRQ(ierr);
3598*0a96aa3bSJed Brown     ierr = DMPforestGetPlex(adapt,&adaptPlex);CHKERRQ(ierr);
3599*0a96aa3bSJed Brown     ierr = DMPforestGetTransferSF(adapt,dm,dofPerDim,&transferForward,&transferBackward);CHKERRQ(ierr);
3600*0a96aa3bSJed Brown     ierr = DMPlexGetChart(plex,&pStart,&pEnd);CHKERRQ(ierr);
3601*0a96aa3bSJed Brown     ierr = DMPlexGetChart(adaptPlex,&pStartA,&pEndA);CHKERRQ(ierr);
3602*0a96aa3bSJed Brown     ierr = PetscMalloc2(pEnd-pStart,&values,pEndA-pStartA,&adaptValues);CHKERRQ(ierr);
3603*0a96aa3bSJed Brown     ierr = DMGetPointSF(plex,&pointSF);CHKERRQ(ierr);
3604*0a96aa3bSJed Brown     if (PetscDefined(USE_DEBUG)) {
3605*0a96aa3bSJed Brown       PetscInt p;
3606*0a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) adaptValues[p-pStartA] = -1;
3607*0a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++)   values[p-pStart]       = -2;
3608*0a96aa3bSJed Brown       if (transferForward) {
3609*0a96aa3bSJed Brown         ierr = PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE);CHKERRQ(ierr);
3610*0a96aa3bSJed Brown         ierr = PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE);CHKERRQ(ierr);
3611*0a96aa3bSJed Brown       }
3612*0a96aa3bSJed Brown       if (transferBackward) {
3613*0a96aa3bSJed Brown         ierr = PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX);CHKERRQ(ierr);
3614*0a96aa3bSJed Brown         ierr = PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX);CHKERRQ(ierr);
3615*0a96aa3bSJed Brown       }
3616*0a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
3617*0a96aa3bSJed Brown         PetscInt q = p, parent;
3618*0a96aa3bSJed Brown 
3619*0a96aa3bSJed Brown         ierr = DMPlexGetTreeParent(plex,q,&parent,NULL);CHKERRQ(ierr);
3620*0a96aa3bSJed Brown         while (parent != q) {
3621*0a96aa3bSJed Brown           if (values[parent] == -2) values[parent] = values[q];
3622*0a96aa3bSJed Brown           q    = parent;
3623*0a96aa3bSJed Brown           ierr = DMPlexGetTreeParent(plex,q,&parent,NULL);CHKERRQ(ierr);
3624*0a96aa3bSJed Brown         }
3625*0a96aa3bSJed Brown       }
3626*0a96aa3bSJed Brown       ierr = PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX);CHKERRQ(ierr);
3627*0a96aa3bSJed Brown       ierr = PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX);CHKERRQ(ierr);
3628*0a96aa3bSJed Brown       ierr = PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE);CHKERRQ(ierr);
3629*0a96aa3bSJed Brown       ierr = PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE);CHKERRQ(ierr);
3630*0a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
3631*0a96aa3bSJed Brown         if (values[p-pStart] == -2) SETERRQ1(PETSC_COMM_SELF,PETSC_ERR_PLIB,"uncovered point %D",p);
3632*0a96aa3bSJed Brown       }
3633*0a96aa3bSJed Brown     }
3634*0a96aa3bSJed Brown     while (next) {
3635*0a96aa3bSJed Brown       DMLabel    nextLabel = next->label;
3636*0a96aa3bSJed Brown       const char *name;
3637*0a96aa3bSJed Brown       PetscBool  isDepth, isCellType, isGhost, isVTK;
3638*0a96aa3bSJed Brown       DMLabel    label;
3639*0a96aa3bSJed Brown       PetscInt   p;
3640*0a96aa3bSJed Brown 
3641*0a96aa3bSJed Brown       ierr = PetscObjectGetName((PetscObject) nextLabel, &name);CHKERRQ(ierr);
3642*0a96aa3bSJed Brown       ierr = PetscStrcmp(name,"depth",&isDepth);CHKERRQ(ierr);
3643*0a96aa3bSJed Brown       if (isDepth) {
3644*0a96aa3bSJed Brown         next = next->next;
3645*0a96aa3bSJed Brown         continue;
3646*0a96aa3bSJed Brown       }
3647*0a96aa3bSJed Brown       ierr = PetscStrcmp(name,"celltype",&isCellType);CHKERRQ(ierr);
3648*0a96aa3bSJed Brown       if (isCellType) {
3649*0a96aa3bSJed Brown         next = next->next;
3650*0a96aa3bSJed Brown         continue;
3651*0a96aa3bSJed Brown       }
3652*0a96aa3bSJed Brown       ierr = PetscStrcmp(name,"ghost",&isGhost);CHKERRQ(ierr);
3653*0a96aa3bSJed Brown       if (isGhost) {
3654*0a96aa3bSJed Brown         next = next->next;
3655*0a96aa3bSJed Brown         continue;
3656*0a96aa3bSJed Brown       }
3657*0a96aa3bSJed Brown       ierr = PetscStrcmp(name,"vtk",&isVTK);CHKERRQ(ierr);
3658*0a96aa3bSJed Brown       if (isVTK) {
3659*0a96aa3bSJed Brown         next = next->next;
3660*0a96aa3bSJed Brown         continue;
3661*0a96aa3bSJed Brown       }
3662*0a96aa3bSJed Brown       if (nextLabel == adaptLabel) {
3663*0a96aa3bSJed Brown         next = next->next;
3664*0a96aa3bSJed Brown         continue;
3665*0a96aa3bSJed Brown       }
3666*0a96aa3bSJed Brown       /* label was created earlier */
3667*0a96aa3bSJed Brown       ierr = DMGetLabel(dm,name,&label);CHKERRQ(ierr);
3668*0a96aa3bSJed Brown       for (p = pStartA; p < pEndA; p++) {
3669*0a96aa3bSJed Brown         ierr = DMLabelGetValue(nextLabel,p,&adaptValues[p]);CHKERRQ(ierr);
3670*0a96aa3bSJed Brown       }
3671*0a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) values[p] = PETSC_MIN_INT;
3672*0a96aa3bSJed Brown 
3673*0a96aa3bSJed Brown       if (transferForward) {
3674*0a96aa3bSJed Brown         ierr = PetscSFBcastBegin(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE);CHKERRQ(ierr);
3675*0a96aa3bSJed Brown       }
3676*0a96aa3bSJed Brown       if (transferBackward) {
3677*0a96aa3bSJed Brown         ierr = PetscSFReduceBegin(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX);CHKERRQ(ierr);
3678*0a96aa3bSJed Brown       }
3679*0a96aa3bSJed Brown       if (transferForward) {
3680*0a96aa3bSJed Brown         ierr = PetscSFBcastEnd(transferForward,MPIU_INT,adaptValues,values,MPI_REPLACE);CHKERRQ(ierr);
3681*0a96aa3bSJed Brown       }
3682*0a96aa3bSJed Brown       if (transferBackward) {
3683*0a96aa3bSJed Brown         ierr = PetscSFReduceEnd(transferBackward,MPIU_INT,adaptValues,values,MPIU_MAX);CHKERRQ(ierr);
3684*0a96aa3bSJed Brown       }
3685*0a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
3686*0a96aa3bSJed Brown         PetscInt q = p, parent;
3687*0a96aa3bSJed Brown 
3688*0a96aa3bSJed Brown         ierr = DMPlexGetTreeParent(plex,q,&parent,NULL);CHKERRQ(ierr);
3689*0a96aa3bSJed Brown         while (parent != q) {
3690*0a96aa3bSJed Brown           if (values[parent] == PETSC_MIN_INT) values[parent] = values[q];
3691*0a96aa3bSJed Brown           q    = parent;
3692*0a96aa3bSJed Brown           ierr = DMPlexGetTreeParent(plex,q,&parent,NULL);CHKERRQ(ierr);
3693*0a96aa3bSJed Brown         }
3694*0a96aa3bSJed Brown       }
3695*0a96aa3bSJed Brown       ierr = PetscSFReduceBegin(pointSF,MPIU_INT,values,values,MPIU_MAX);CHKERRQ(ierr);
3696*0a96aa3bSJed Brown       ierr = PetscSFReduceEnd(pointSF,MPIU_INT,values,values,MPIU_MAX);CHKERRQ(ierr);
3697*0a96aa3bSJed Brown       ierr = PetscSFBcastBegin(pointSF,MPIU_INT,values,values,MPI_REPLACE);CHKERRQ(ierr);
3698*0a96aa3bSJed Brown       ierr = PetscSFBcastEnd(pointSF,MPIU_INT,values,values,MPI_REPLACE);CHKERRQ(ierr);
3699*0a96aa3bSJed Brown 
3700*0a96aa3bSJed Brown       for (p = pStart; p < pEnd; p++) {
3701*0a96aa3bSJed Brown         ierr = DMLabelSetValue(label,p,values[p]);CHKERRQ(ierr);
3702*0a96aa3bSJed Brown       }
3703*0a96aa3bSJed Brown       next = next->next;
3704*0a96aa3bSJed Brown     }
3705*0a96aa3bSJed Brown     ierr                     = PetscFree2(values,adaptValues);CHKERRQ(ierr);
3706*0a96aa3bSJed Brown     ierr                     = PetscSFDestroy(&transferForward);CHKERRQ(ierr);
3707*0a96aa3bSJed Brown     ierr                     = PetscSFDestroy(&transferBackward);CHKERRQ(ierr);
3708*0a96aa3bSJed Brown     pforest->labelsFinalized = PETSC_TRUE;
3709*0a96aa3bSJed Brown   }
3710*0a96aa3bSJed Brown   PetscFunctionReturn(0);
3711*0a96aa3bSJed Brown }
3712*0a96aa3bSJed Brown 
3713*0a96aa3bSJed 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)
3714*0a96aa3bSJed Brown {
3715*0a96aa3bSJed Brown   PetscInt       closureSize, c, coordStart, coordEnd, coordDim;
3716*0a96aa3bSJed Brown   PetscInt       *closure = NULL;
3717*0a96aa3bSJed Brown   PetscSection   coordSec;
3718*0a96aa3bSJed Brown   PetscErrorCode ierr;
3719*0a96aa3bSJed Brown 
3720*0a96aa3bSJed Brown   PetscFunctionBegin;
3721*0a96aa3bSJed Brown   ierr          = DMGetCoordinateSection(plex,&coordSec);CHKERRQ(ierr);
3722*0a96aa3bSJed Brown   ierr          = PetscSectionGetChart(coordSec,&coordStart,&coordEnd);CHKERRQ(ierr);
3723*0a96aa3bSJed Brown   ierr          = DMGetCoordinateDim(plex,&coordDim);CHKERRQ(ierr);
3724*0a96aa3bSJed Brown   ierr          = DMPlexGetTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
3725*0a96aa3bSJed Brown   for (c = 0; c < closureSize; c++) {
3726*0a96aa3bSJed Brown     PetscInt point = closure[2 * c];
3727*0a96aa3bSJed Brown 
3728*0a96aa3bSJed Brown     if (point >= coordStart && point < coordEnd) {
3729*0a96aa3bSJed Brown       PetscInt dof, off;
3730*0a96aa3bSJed Brown       PetscInt nCoords, i;
3731*0a96aa3bSJed Brown       ierr = PetscSectionGetDof(coordSec,point,&dof);CHKERRQ(ierr);
3732*0a96aa3bSJed Brown       if (dof % coordDim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
3733*0a96aa3bSJed Brown       nCoords = dof / coordDim;
3734*0a96aa3bSJed Brown       ierr    = PetscSectionGetOffset(coordSec,point,&off);CHKERRQ(ierr);
3735*0a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
3736*0a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
3737*0a96aa3bSJed Brown         double      coordP4est[3]       = {0.};
3738*0a96aa3bSJed Brown         double      coordP4estMapped[3] = {0.};
3739*0a96aa3bSJed Brown         PetscInt    j;
3740*0a96aa3bSJed Brown         PetscReal   treeCoords[P4EST_CHILDREN][3] = {{0.}};
3741*0a96aa3bSJed Brown         PetscReal   eta[3]                        = {0.};
3742*0a96aa3bSJed Brown         PetscInt    numRounds                     = 10;
3743*0a96aa3bSJed Brown         PetscReal   coordGuess[3]                 = {0.};
3744*0a96aa3bSJed Brown 
3745*0a96aa3bSJed Brown         eta[0] = (PetscReal) q->x / (PetscReal) P4EST_ROOT_LEN;
3746*0a96aa3bSJed Brown         eta[1] = (PetscReal) q->y / (PetscReal) P4EST_ROOT_LEN;
3747*0a96aa3bSJed Brown #if defined(P4_TO_P8)
3748*0a96aa3bSJed Brown         eta[2] = (PetscReal) q->z / (PetscReal) P4EST_ROOT_LEN;
3749*0a96aa3bSJed Brown #endif
3750*0a96aa3bSJed Brown 
3751*0a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
3752*0a96aa3bSJed Brown           PetscInt k;
3753*0a96aa3bSJed Brown 
3754*0a96aa3bSJed Brown           for (k = 0; k < 3; k++) treeCoords[j][k] = conn->vertices[3 * conn->tree_to_vertex[P4EST_CHILDREN * t + j] + k];
3755*0a96aa3bSJed Brown         }
3756*0a96aa3bSJed Brown 
3757*0a96aa3bSJed Brown         for (j = 0; j < P4EST_CHILDREN; j++) {
3758*0a96aa3bSJed Brown           PetscInt  k;
3759*0a96aa3bSJed Brown           PetscReal prod = 1.;
3760*0a96aa3bSJed Brown 
3761*0a96aa3bSJed Brown           for (k = 0; k < P4EST_DIM; k++) prod *= (j & (1 << k)) ? eta[k] : (1. - eta[k]);
3762*0a96aa3bSJed Brown           for (k = 0; k < 3; k++) coordGuess[k] += prod * treeCoords[j][k];
3763*0a96aa3bSJed Brown         }
3764*0a96aa3bSJed Brown 
3765*0a96aa3bSJed Brown         for (j = 0; j < numRounds; j++) {
3766*0a96aa3bSJed Brown           PetscInt dir;
3767*0a96aa3bSJed Brown 
3768*0a96aa3bSJed Brown           for (dir = 0; dir < P4EST_DIM; dir++) {
3769*0a96aa3bSJed Brown             PetscInt  k;
3770*0a96aa3bSJed Brown             PetscReal diff[3];
3771*0a96aa3bSJed Brown             PetscReal dXdeta[3] = {0.};
3772*0a96aa3bSJed Brown             PetscReal rhs, scale, update;
3773*0a96aa3bSJed Brown 
3774*0a96aa3bSJed Brown             for (k = 0; k < 3; k++) diff[k] = coordP4est[k] - coordGuess[k];
3775*0a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
3776*0a96aa3bSJed Brown               PetscInt  l;
3777*0a96aa3bSJed Brown               PetscReal prod = 1.;
3778*0a96aa3bSJed Brown 
3779*0a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) {
3780*0a96aa3bSJed Brown                 if (l == dir) {
3781*0a96aa3bSJed Brown                   prod *= (k & (1 << l)) ?  1. : -1.;
3782*0a96aa3bSJed Brown                 } else {
3783*0a96aa3bSJed Brown                   prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
3784*0a96aa3bSJed Brown                 }
3785*0a96aa3bSJed Brown               }
3786*0a96aa3bSJed Brown               for (l = 0; l < 3; l++) dXdeta[l] += prod * treeCoords[k][l];
3787*0a96aa3bSJed Brown             }
3788*0a96aa3bSJed Brown             rhs   = 0.;
3789*0a96aa3bSJed Brown             scale = 0;
3790*0a96aa3bSJed Brown             for (k = 0; k < 3; k++) {
3791*0a96aa3bSJed Brown               rhs   += diff[k] * dXdeta[k];
3792*0a96aa3bSJed Brown               scale += dXdeta[k] * dXdeta[k];
3793*0a96aa3bSJed Brown             }
3794*0a96aa3bSJed Brown             update    = rhs / scale;
3795*0a96aa3bSJed Brown             eta[dir] += update;
3796*0a96aa3bSJed Brown             eta[dir]  = PetscMin(eta[dir],1.);
3797*0a96aa3bSJed Brown             eta[dir]  = PetscMax(eta[dir],0.);
3798*0a96aa3bSJed Brown 
3799*0a96aa3bSJed Brown             coordGuess[0] = coordGuess[1] = coordGuess[2] = 0.;
3800*0a96aa3bSJed Brown             for (k = 0; k < P4EST_CHILDREN; k++) {
3801*0a96aa3bSJed Brown               PetscInt  l;
3802*0a96aa3bSJed Brown               PetscReal prod = 1.;
3803*0a96aa3bSJed Brown 
3804*0a96aa3bSJed Brown               for (l = 0; l < P4EST_DIM; l++) prod *= (k & (1 << l)) ? eta[l] : (1. - eta[l]);
3805*0a96aa3bSJed Brown               for (l = 0; l < 3; l++) coordGuess[l] += prod * treeCoords[k][l];
3806*0a96aa3bSJed Brown             }
3807*0a96aa3bSJed Brown           }
3808*0a96aa3bSJed Brown         }
3809*0a96aa3bSJed Brown         for (j = 0; j < 3; j++) coordP4est[j] = (double) eta[j];
3810*0a96aa3bSJed Brown 
3811*0a96aa3bSJed Brown         if (geom) {
3812*0a96aa3bSJed Brown           (geom->X)(geom,t,coordP4est,coordP4estMapped);
3813*0a96aa3bSJed Brown           for (j = 0; j < coordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
3814*0a96aa3bSJed Brown         } else SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not coded");
3815*0a96aa3bSJed Brown       }
3816*0a96aa3bSJed Brown     }
3817*0a96aa3bSJed Brown   }
3818*0a96aa3bSJed Brown   ierr = DMPlexRestoreTransitiveClosure(plex,cell,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
3819*0a96aa3bSJed Brown   PetscFunctionReturn(0);
3820*0a96aa3bSJed Brown }
3821*0a96aa3bSJed Brown 
3822*0a96aa3bSJed Brown static PetscErrorCode DMPforestMapCoordinates(DM dm, DM plex)
3823*0a96aa3bSJed Brown {
3824*0a96aa3bSJed Brown   DM_Forest         *forest;
3825*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
3826*0a96aa3bSJed Brown   p4est_geometry_t  *geom;
3827*0a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd;
3828*0a96aa3bSJed Brown   Vec               coordLocalVec;
3829*0a96aa3bSJed Brown   PetscScalar       *coords;
3830*0a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
3831*0a96aa3bSJed Brown   p4est_tree_t      *trees;
3832*0a96aa3bSJed Brown   PetscErrorCode    (*map)(DM,PetscInt, PetscInt, const PetscReal [], PetscReal [], void*);
3833*0a96aa3bSJed Brown   void              *mapCtx;
3834*0a96aa3bSJed Brown   PetscErrorCode    ierr;
3835*0a96aa3bSJed Brown 
3836*0a96aa3bSJed Brown   PetscFunctionBegin;
3837*0a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
3838*0a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
3839*0a96aa3bSJed Brown   geom    = pforest->topo->geom;
3840*0a96aa3bSJed Brown   ierr    = DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx);CHKERRQ(ierr);
3841*0a96aa3bSJed Brown   if (!geom && !map) PetscFunctionReturn(0);
3842*0a96aa3bSJed Brown   ierr        = DMGetCoordinatesLocal(plex,&coordLocalVec);CHKERRQ(ierr);
3843*0a96aa3bSJed Brown   ierr        = VecGetArray(coordLocalVec,&coords);CHKERRQ(ierr);
3844*0a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
3845*0a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
3846*0a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
3847*0a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
3848*0a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
3849*0a96aa3bSJed Brown   if (map) { /* apply the map directly to the existing coordinates */
3850*0a96aa3bSJed Brown     PetscSection coordSec;
3851*0a96aa3bSJed Brown     PetscInt     coordStart, coordEnd, p, coordDim, p4estCoordDim, cStart, cEnd, cEndInterior;
3852*0a96aa3bSJed Brown     DM           base;
3853*0a96aa3bSJed Brown 
3854*0a96aa3bSJed Brown     ierr          = DMPlexGetHeightStratum(plex,0,&cStart,&cEnd);CHKERRQ(ierr);
3855*0a96aa3bSJed Brown     ierr          = DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL);CHKERRQ(ierr);
3856*0a96aa3bSJed Brown     cEnd          = cEndInterior < 0 ? cEnd : cEndInterior;
3857*0a96aa3bSJed Brown     ierr          = DMForestGetBaseDM(dm,&base);CHKERRQ(ierr);
3858*0a96aa3bSJed Brown     ierr          = DMGetCoordinateSection(plex,&coordSec);CHKERRQ(ierr);
3859*0a96aa3bSJed Brown     ierr          = PetscSectionGetChart(coordSec,&coordStart,&coordEnd);CHKERRQ(ierr);
3860*0a96aa3bSJed Brown     ierr          = DMGetCoordinateDim(plex,&coordDim);CHKERRQ(ierr);
3861*0a96aa3bSJed Brown     p4estCoordDim = PetscMin(coordDim,3);
3862*0a96aa3bSJed Brown     for (p = coordStart; p < coordEnd; p++) {
3863*0a96aa3bSJed Brown       PetscInt *star = NULL, starSize;
3864*0a96aa3bSJed Brown       PetscInt dof, off, cell = -1, coarsePoint = -1;
3865*0a96aa3bSJed Brown       PetscInt nCoords, i;
3866*0a96aa3bSJed Brown       ierr = PetscSectionGetDof(coordSec,p,&dof);CHKERRQ(ierr);
3867*0a96aa3bSJed Brown       if (dof % coordDim) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Did not understand coordinate layout");
3868*0a96aa3bSJed Brown       nCoords = dof / coordDim;
3869*0a96aa3bSJed Brown       ierr    = PetscSectionGetOffset(coordSec,p,&off);CHKERRQ(ierr);
3870*0a96aa3bSJed Brown       ierr    = DMPlexGetTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
3871*0a96aa3bSJed Brown       for (i = 0; i < starSize; i++) {
3872*0a96aa3bSJed Brown         PetscInt point = star[2 * i];
3873*0a96aa3bSJed Brown 
3874*0a96aa3bSJed Brown         if (cStart <= point && point < cEnd) {
3875*0a96aa3bSJed Brown           cell = point;
3876*0a96aa3bSJed Brown           break;
3877*0a96aa3bSJed Brown         }
3878*0a96aa3bSJed Brown       }
3879*0a96aa3bSJed Brown       ierr = DMPlexRestoreTransitiveClosure(plex,p,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
3880*0a96aa3bSJed Brown       if (cell >= 0) {
3881*0a96aa3bSJed Brown         if (cell < cLocalStart) {
3882*0a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
3883*0a96aa3bSJed Brown 
3884*0a96aa3bSJed Brown           coarsePoint = ghosts[cell].p.which_tree;
3885*0a96aa3bSJed Brown         } else if (cell < cLocalEnd) {
3886*0a96aa3bSJed Brown           cell -= cLocalStart;
3887*0a96aa3bSJed Brown           for (t = flt; t <= llt; t++) {
3888*0a96aa3bSJed Brown             p4est_tree_t *tree = &(trees[t]);
3889*0a96aa3bSJed Brown 
3890*0a96aa3bSJed Brown             if (cell >= tree->quadrants_offset && (size_t) cell < tree->quadrants_offset + tree->quadrants.elem_count) {
3891*0a96aa3bSJed Brown               coarsePoint = t;
3892*0a96aa3bSJed Brown               break;
3893*0a96aa3bSJed Brown             }
3894*0a96aa3bSJed Brown           }
3895*0a96aa3bSJed Brown         } else {
3896*0a96aa3bSJed Brown           p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
3897*0a96aa3bSJed Brown 
3898*0a96aa3bSJed Brown           coarsePoint = ghosts[cell - cLocalEnd].p.which_tree;
3899*0a96aa3bSJed Brown         }
3900*0a96aa3bSJed Brown       }
3901*0a96aa3bSJed Brown       for (i = 0; i < nCoords; i++) {
3902*0a96aa3bSJed Brown         PetscScalar *coord              = &coords[off + i * coordDim];
3903*0a96aa3bSJed Brown         PetscReal   coordP4est[3]       = {0.};
3904*0a96aa3bSJed Brown         PetscReal   coordP4estMapped[3] = {0.};
3905*0a96aa3bSJed Brown         PetscInt    j;
3906*0a96aa3bSJed Brown 
3907*0a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coordP4est[j] = PetscRealPart(coord[j]);
3908*0a96aa3bSJed Brown         ierr = (map)(base,coarsePoint,p4estCoordDim,coordP4est,coordP4estMapped,mapCtx);CHKERRQ(ierr);
3909*0a96aa3bSJed Brown         for (j = 0; j < p4estCoordDim; j++) coord[j] = (PetscScalar) coordP4estMapped[j];
3910*0a96aa3bSJed Brown       }
3911*0a96aa3bSJed Brown     }
3912*0a96aa3bSJed Brown   } else { /* we have to transform coordinates back to the unit cube (where geom is defined), and then apply geom */
3913*0a96aa3bSJed Brown     PetscInt cStart, cEnd, cEndInterior;
3914*0a96aa3bSJed Brown 
3915*0a96aa3bSJed Brown     ierr = DMPlexGetHeightStratum(plex,0,&cStart,&cEnd);CHKERRQ(ierr);
3916*0a96aa3bSJed Brown     ierr = DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL);CHKERRQ(ierr);
3917*0a96aa3bSJed Brown     cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
3918*0a96aa3bSJed Brown     if (cLocalStart > 0) {
3919*0a96aa3bSJed Brown       p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
3920*0a96aa3bSJed Brown       PetscInt         count;
3921*0a96aa3bSJed Brown 
3922*0a96aa3bSJed Brown       for (count = 0; count < cLocalStart; count++) {
3923*0a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count];
3924*0a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
3925*0a96aa3bSJed Brown 
3926*0a96aa3bSJed Brown         ierr = DMPforestMapCoordinates_Cell(plex,geom,count,quad,t,pforest->topo->conn,coords);CHKERRQ(ierr);
3927*0a96aa3bSJed Brown       }
3928*0a96aa3bSJed Brown     }
3929*0a96aa3bSJed Brown     for (t = flt; t <= llt; t++) {
3930*0a96aa3bSJed Brown       p4est_tree_t     *tree    = &(trees[t]);
3931*0a96aa3bSJed Brown       PetscInt         offset   = cLocalStart + tree->quadrants_offset, i;
3932*0a96aa3bSJed Brown       PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
3933*0a96aa3bSJed Brown       p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
3934*0a96aa3bSJed Brown 
3935*0a96aa3bSJed Brown       for (i = 0; i < numQuads; i++) {
3936*0a96aa3bSJed Brown         PetscInt count = i + offset;
3937*0a96aa3bSJed Brown 
3938*0a96aa3bSJed Brown         ierr = DMPforestMapCoordinates_Cell(plex,geom,count,&quads[i],t,pforest->topo->conn,coords);CHKERRQ(ierr);
3939*0a96aa3bSJed Brown       }
3940*0a96aa3bSJed Brown     }
3941*0a96aa3bSJed Brown     if (cLocalEnd - cLocalStart < cEnd - cStart) {
3942*0a96aa3bSJed Brown       p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
3943*0a96aa3bSJed Brown       PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
3944*0a96aa3bSJed Brown       PetscInt         count;
3945*0a96aa3bSJed Brown 
3946*0a96aa3bSJed Brown       for (count = 0; count < numGhosts - cLocalStart; count++) {
3947*0a96aa3bSJed Brown         p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
3948*0a96aa3bSJed Brown         p4est_topidx_t   t     = quad->p.which_tree;
3949*0a96aa3bSJed Brown 
3950*0a96aa3bSJed Brown         ierr = DMPforestMapCoordinates_Cell(plex,geom,count + cLocalEnd,quad,t,pforest->topo->conn,coords);CHKERRQ(ierr);
3951*0a96aa3bSJed Brown       }
3952*0a96aa3bSJed Brown     }
3953*0a96aa3bSJed Brown   }
3954*0a96aa3bSJed Brown   ierr = VecRestoreArray(coordLocalVec,&coords);CHKERRQ(ierr);
3955*0a96aa3bSJed Brown   PetscFunctionReturn(0);
3956*0a96aa3bSJed Brown }
3957*0a96aa3bSJed Brown 
3958*0a96aa3bSJed Brown static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
3959*0a96aa3bSJed Brown {
3960*0a96aa3bSJed Brown   DM_Forest         *forest;
3961*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
3962*0a96aa3bSJed Brown   DM                base;
3963*0a96aa3bSJed Brown   Vec               coordinates, cVec;
3964*0a96aa3bSJed Brown   PetscSection      oldSection, baseSection = NULL, newSection;
3965*0a96aa3bSJed Brown   const PetscScalar *coords;
3966*0a96aa3bSJed Brown   PetscScalar       *coords2;
3967*0a96aa3bSJed Brown   PetscInt          cLocalStart, cLocalEnd, coarsePoint;
3968*0a96aa3bSJed Brown   PetscInt          cDim, newStart, newEnd, dof, cdof = -1;
3969*0a96aa3bSJed Brown   PetscInt          v, vStart, vEnd, cp, cStart, cEnd, cEndInterior, *coarsePoints;
3970*0a96aa3bSJed Brown   PetscInt          *localize, overlap;
3971*0a96aa3bSJed Brown   p4est_topidx_t    flt, llt, t;
3972*0a96aa3bSJed Brown   p4est_tree_t      *trees;
3973*0a96aa3bSJed Brown   PetscBool         isper, baseLocalized = PETSC_FALSE;
3974*0a96aa3bSJed Brown   PetscErrorCode    ierr;
3975*0a96aa3bSJed Brown 
3976*0a96aa3bSJed Brown   PetscFunctionBegin;
3977*0a96aa3bSJed Brown   ierr = DMGetPeriodicity(dm,&isper,NULL,NULL,NULL);CHKERRQ(ierr);
3978*0a96aa3bSJed Brown   if (!isper) PetscFunctionReturn(0);
3979*0a96aa3bSJed Brown   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
3980*0a96aa3bSJed Brown   ierr = DMGetCoordinateDim(dm, &cDim);CHKERRQ(ierr);
3981*0a96aa3bSJed Brown   cdof = P4EST_CHILDREN*cDim;
3982*0a96aa3bSJed Brown   ierr = DMForestGetBaseDM(dm,&base);CHKERRQ(ierr);
3983*0a96aa3bSJed Brown   if (base) {
3984*0a96aa3bSJed Brown     ierr = DMGetCoordinatesLocalized(base,&baseLocalized);CHKERRQ(ierr);
3985*0a96aa3bSJed Brown   }
3986*0a96aa3bSJed Brown   if (!baseLocalized) base = NULL;
3987*0a96aa3bSJed Brown   ierr = DMPlexGetChart(plex, &newStart, &newEnd);CHKERRQ(ierr);
3988*0a96aa3bSJed Brown 
3989*0a96aa3bSJed Brown   ierr = DMForestGetPartitionOverlap(dm,&overlap);CHKERRQ(ierr);
3990*0a96aa3bSJed Brown   ierr = PetscCalloc1(overlap ? newEnd - newStart : 0,&localize);CHKERRQ(ierr);
3991*0a96aa3bSJed Brown 
3992*0a96aa3bSJed Brown   ierr = PetscSectionCreate(PetscObjectComm((PetscObject) dm), &newSection);CHKERRQ(ierr);
3993*0a96aa3bSJed Brown   ierr = PetscSectionSetNumFields(newSection, 1);CHKERRQ(ierr);
3994*0a96aa3bSJed Brown   ierr = PetscSectionSetFieldComponents(newSection, 0, cDim);CHKERRQ(ierr);
3995*0a96aa3bSJed Brown   ierr = PetscSectionSetChart(newSection, newStart, newEnd);CHKERRQ(ierr);
3996*0a96aa3bSJed Brown 
3997*0a96aa3bSJed Brown   ierr = DMGetCoordinateSection(plex, &oldSection);CHKERRQ(ierr);
3998*0a96aa3bSJed Brown   if (base) { ierr = DMGetCoordinateSection(base, &baseSection);CHKERRQ(ierr); }
3999*0a96aa3bSJed Brown   ierr = DMPlexGetDepthStratum(plex,0,&vStart,&vEnd);CHKERRQ(ierr);
4000*0a96aa3bSJed Brown   for (v = vStart; v < vEnd; ++v) {
4001*0a96aa3bSJed Brown     ierr = PetscSectionGetDof(oldSection, v, &dof);CHKERRQ(ierr);
4002*0a96aa3bSJed Brown     ierr = PetscSectionSetDof(newSection, v, dof);CHKERRQ(ierr);
4003*0a96aa3bSJed Brown     ierr = PetscSectionSetFieldDof(newSection, v, 0, dof);CHKERRQ(ierr);
4004*0a96aa3bSJed Brown     if (overlap) localize[v] = dof;
4005*0a96aa3bSJed Brown   }
4006*0a96aa3bSJed Brown 
4007*0a96aa3bSJed Brown   forest      = (DM_Forest*) dm->data;
4008*0a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
4009*0a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
4010*0a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
4011*0a96aa3bSJed Brown   flt         = pforest->forest->first_local_tree;
4012*0a96aa3bSJed Brown   llt         = pforest->forest->last_local_tree;
4013*0a96aa3bSJed Brown   trees       = (p4est_tree_t*) pforest->forest->trees->array;
4014*0a96aa3bSJed Brown 
4015*0a96aa3bSJed Brown   cp = 0;
4016*0a96aa3bSJed Brown   ierr = DMPlexGetHeightStratum(plex,0,&cStart,&cEnd);CHKERRQ(ierr);
4017*0a96aa3bSJed Brown   ierr = DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL);CHKERRQ(ierr);
4018*0a96aa3bSJed Brown   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
4019*0a96aa3bSJed Brown   ierr = PetscMalloc1(cEnd-cStart,&coarsePoints);CHKERRQ(ierr);
4020*0a96aa3bSJed Brown   if (cLocalStart > 0) {
4021*0a96aa3bSJed Brown     p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4022*0a96aa3bSJed Brown     PetscInt         count;
4023*0a96aa3bSJed Brown 
4024*0a96aa3bSJed Brown     for (count = 0; count < cLocalStart; count++) {
4025*0a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count];
4026*0a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
4027*0a96aa3bSJed Brown 
4028*0a96aa3bSJed Brown       if (baseSection) { ierr = PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof);CHKERRQ(ierr); }
4029*0a96aa3bSJed Brown       ierr = PetscSectionSetDof(newSection, count, cdof);CHKERRQ(ierr);
4030*0a96aa3bSJed Brown       ierr = PetscSectionSetFieldDof(newSection, count, 0, cdof);CHKERRQ(ierr);
4031*0a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
4032*0a96aa3bSJed Brown       if (overlap) localize[count] = cdof;
4033*0a96aa3bSJed Brown     }
4034*0a96aa3bSJed Brown   }
4035*0a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
4036*0a96aa3bSJed Brown     p4est_tree_t *tree    = &(trees[t]);
4037*0a96aa3bSJed Brown     PetscInt     offset   = cLocalStart + tree->quadrants_offset;
4038*0a96aa3bSJed Brown     PetscInt     numQuads = (PetscInt) tree->quadrants.elem_count;
4039*0a96aa3bSJed Brown     PetscInt     i;
4040*0a96aa3bSJed Brown 
4041*0a96aa3bSJed Brown     if (!numQuads) continue;
4042*0a96aa3bSJed Brown     coarsePoint = t;
4043*0a96aa3bSJed Brown     if (baseSection) { ierr = PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof);CHKERRQ(ierr); }
4044*0a96aa3bSJed Brown     for (i = 0; i < numQuads; i++) {
4045*0a96aa3bSJed Brown       PetscInt newCell = i + offset;
4046*0a96aa3bSJed Brown 
4047*0a96aa3bSJed Brown       ierr = PetscSectionSetDof(newSection, newCell, cdof);CHKERRQ(ierr);
4048*0a96aa3bSJed Brown       ierr = PetscSectionSetFieldDof(newSection, newCell, 0, cdof);CHKERRQ(ierr);
4049*0a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
4050*0a96aa3bSJed Brown       if (overlap) localize[newCell] = cdof;
4051*0a96aa3bSJed Brown     }
4052*0a96aa3bSJed Brown   }
4053*0a96aa3bSJed Brown   if (cLocalEnd - cLocalStart < cEnd - cStart) {
4054*0a96aa3bSJed Brown     p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4055*0a96aa3bSJed Brown     PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
4056*0a96aa3bSJed Brown     PetscInt         count;
4057*0a96aa3bSJed Brown 
4058*0a96aa3bSJed Brown     for (count = 0; count < numGhosts - cLocalStart; count++) {
4059*0a96aa3bSJed Brown       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
4060*0a96aa3bSJed Brown       coarsePoint = quad->p.which_tree;
4061*0a96aa3bSJed Brown       PetscInt newCell = count + cLocalEnd;
4062*0a96aa3bSJed Brown 
4063*0a96aa3bSJed Brown       if (baseSection) { ierr = PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof);CHKERRQ(ierr); }
4064*0a96aa3bSJed Brown       ierr = PetscSectionSetDof(newSection, newCell, cdof);CHKERRQ(ierr);
4065*0a96aa3bSJed Brown       ierr = PetscSectionSetFieldDof(newSection, newCell, 0, cdof);CHKERRQ(ierr);
4066*0a96aa3bSJed Brown       coarsePoints[cp++] = cdof ? coarsePoint : -1;
4067*0a96aa3bSJed Brown       if (overlap) localize[newCell] = cdof;
4068*0a96aa3bSJed Brown     }
4069*0a96aa3bSJed Brown   }
4070*0a96aa3bSJed Brown   if (cp != cEnd - cStart) SETERRQ2(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected number of fine cells %D != %D",cp,cEnd-cStart);
4071*0a96aa3bSJed Brown 
4072*0a96aa3bSJed Brown   if (base) { /* we need to localize on all the cells in the star of the coarse cell vertices */
4073*0a96aa3bSJed Brown     PetscInt *closure = NULL, closureSize;
4074*0a96aa3bSJed Brown     PetscInt p, i, c, vStartBase, vEndBase, cStartBase, cEndBase;
4075*0a96aa3bSJed Brown 
4076*0a96aa3bSJed Brown     ierr = DMPlexGetHeightStratum(base,0,&cStartBase,&cEndBase);CHKERRQ(ierr);
4077*0a96aa3bSJed Brown     ierr = DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase);CHKERRQ(ierr);
4078*0a96aa3bSJed Brown     for (p = cStart; p < cEnd; p++) {
4079*0a96aa3bSJed Brown       coarsePoint = coarsePoints[p-cStart];
4080*0a96aa3bSJed Brown       if (coarsePoint < 0) continue;
4081*0a96aa3bSJed Brown       if (baseSection) { ierr = PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof);CHKERRQ(ierr); }
4082*0a96aa3bSJed Brown       ierr = DMPlexGetTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
4083*0a96aa3bSJed Brown       for (c = 0; c < closureSize; c++) {
4084*0a96aa3bSJed Brown         PetscInt *star = NULL, starSize;
4085*0a96aa3bSJed Brown         PetscInt j, v = closure[2 * c];
4086*0a96aa3bSJed Brown 
4087*0a96aa3bSJed Brown         if (v < vStartBase || v > vEndBase) continue;
4088*0a96aa3bSJed Brown         ierr = DMPlexGetTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
4089*0a96aa3bSJed Brown         for (j = 0; j < starSize; j++) {
4090*0a96aa3bSJed Brown           PetscInt cell = star[2 * j];
4091*0a96aa3bSJed Brown 
4092*0a96aa3bSJed Brown           if (cStartBase <= cell && cell < cEndBase) {
4093*0a96aa3bSJed Brown             p4est_tree_t *tree;
4094*0a96aa3bSJed Brown             PetscInt     offset,numQuads;
4095*0a96aa3bSJed Brown 
4096*0a96aa3bSJed Brown             if (cell < flt || cell > llt) continue;
4097*0a96aa3bSJed Brown             tree     = &(trees[cell]);
4098*0a96aa3bSJed Brown             offset   = cLocalStart + tree->quadrants_offset;
4099*0a96aa3bSJed Brown             numQuads = (PetscInt) tree->quadrants.elem_count;
4100*0a96aa3bSJed Brown             for (i = 0; i < numQuads; i++) {
4101*0a96aa3bSJed Brown               PetscInt newCell = i + offset;
4102*0a96aa3bSJed Brown 
4103*0a96aa3bSJed Brown               ierr = PetscSectionSetDof(newSection, newCell, cdof);CHKERRQ(ierr);
4104*0a96aa3bSJed Brown               ierr = PetscSectionSetFieldDof(newSection, newCell, 0, cdof);CHKERRQ(ierr);
4105*0a96aa3bSJed Brown               if (overlap) localize[newCell] = cdof;
4106*0a96aa3bSJed Brown             }
4107*0a96aa3bSJed Brown           }
4108*0a96aa3bSJed Brown         }
4109*0a96aa3bSJed Brown         ierr = DMPlexRestoreTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star);CHKERRQ(ierr);
4110*0a96aa3bSJed Brown       }
4111*0a96aa3bSJed Brown       ierr = DMPlexRestoreTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure);CHKERRQ(ierr);
4112*0a96aa3bSJed Brown     }
4113*0a96aa3bSJed Brown   }
4114*0a96aa3bSJed Brown   ierr = PetscFree(coarsePoints);CHKERRQ(ierr);
4115*0a96aa3bSJed Brown 
4116*0a96aa3bSJed Brown   /* final consensus with overlap */
4117*0a96aa3bSJed Brown   if (overlap) {
4118*0a96aa3bSJed Brown     PetscSF  sf;
4119*0a96aa3bSJed Brown     PetscInt *localizeGlobal;
4120*0a96aa3bSJed Brown 
4121*0a96aa3bSJed Brown     ierr = DMGetPointSF(plex,&sf);CHKERRQ(ierr);
4122*0a96aa3bSJed Brown     ierr = PetscMalloc1(newEnd-newStart,&localizeGlobal);CHKERRQ(ierr);
4123*0a96aa3bSJed Brown     for (v = newStart; v < newEnd; v++) localizeGlobal[v - newStart] = localize[v - newStart];
4124*0a96aa3bSJed Brown     ierr = PetscSFBcastBegin(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE);CHKERRQ(ierr);
4125*0a96aa3bSJed Brown     ierr = PetscSFBcastEnd(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE);CHKERRQ(ierr);
4126*0a96aa3bSJed Brown     for (v = newStart; v < newEnd; v++) {
4127*0a96aa3bSJed Brown       ierr = PetscSectionSetDof(newSection, v, localizeGlobal[v-newStart]);CHKERRQ(ierr);
4128*0a96aa3bSJed Brown       ierr = PetscSectionSetFieldDof(newSection, v, 0, localizeGlobal[v-newStart]);CHKERRQ(ierr);
4129*0a96aa3bSJed Brown     }
4130*0a96aa3bSJed Brown     ierr = PetscFree(localizeGlobal);CHKERRQ(ierr);
4131*0a96aa3bSJed Brown   }
4132*0a96aa3bSJed Brown   ierr = PetscFree(localize);CHKERRQ(ierr);
4133*0a96aa3bSJed Brown   ierr = PetscSectionSetUp(newSection);CHKERRQ(ierr);
4134*0a96aa3bSJed Brown   ierr = PetscObjectReference((PetscObject)oldSection);CHKERRQ(ierr);
4135*0a96aa3bSJed Brown   ierr = DMSetCoordinateSection(plex, cDim, newSection);CHKERRQ(ierr);
4136*0a96aa3bSJed Brown   ierr = PetscSectionGetStorageSize(newSection, &v);CHKERRQ(ierr);
4137*0a96aa3bSJed Brown   ierr = VecCreate(PETSC_COMM_SELF, &cVec);CHKERRQ(ierr);
4138*0a96aa3bSJed Brown   ierr = PetscObjectSetName((PetscObject)cVec,"coordinates");CHKERRQ(ierr);
4139*0a96aa3bSJed Brown   ierr = VecSetBlockSize(cVec, cDim);CHKERRQ(ierr);
4140*0a96aa3bSJed Brown   ierr = VecSetSizes(cVec, v, PETSC_DETERMINE);CHKERRQ(ierr);
4141*0a96aa3bSJed Brown   ierr = VecSetType(cVec, VECSTANDARD);CHKERRQ(ierr);
4142*0a96aa3bSJed Brown   ierr = VecSet(cVec, PETSC_MIN_REAL);CHKERRQ(ierr);
4143*0a96aa3bSJed Brown 
4144*0a96aa3bSJed Brown   /* Copy over vertex coordinates */
4145*0a96aa3bSJed Brown   ierr = DMGetCoordinatesLocal(plex, &coordinates);CHKERRQ(ierr);
4146*0a96aa3bSJed Brown   if (!coordinates) SETERRQ(PetscObjectComm((PetscObject)plex),PETSC_ERR_SUP,"Missing local coordinates vector");
4147*0a96aa3bSJed Brown   ierr = VecGetArray(cVec, &coords2);CHKERRQ(ierr);
4148*0a96aa3bSJed Brown   ierr = VecGetArrayRead(coordinates, &coords);CHKERRQ(ierr);
4149*0a96aa3bSJed Brown   for (v = vStart; v < vEnd; ++v) {
4150*0a96aa3bSJed Brown     PetscInt d, off,off2;
4151*0a96aa3bSJed Brown 
4152*0a96aa3bSJed Brown     ierr = PetscSectionGetDof(oldSection, v, &dof);CHKERRQ(ierr);
4153*0a96aa3bSJed Brown     ierr = PetscSectionGetOffset(oldSection, v, &off);CHKERRQ(ierr);
4154*0a96aa3bSJed Brown     ierr = PetscSectionGetOffset(newSection, v, &off2);CHKERRQ(ierr);
4155*0a96aa3bSJed Brown     for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d];
4156*0a96aa3bSJed Brown   }
4157*0a96aa3bSJed Brown   ierr = VecRestoreArrayRead(coordinates, &coords);CHKERRQ(ierr);
4158*0a96aa3bSJed Brown 
4159*0a96aa3bSJed Brown   /* Localize coordinates on cells if needed */
4160*0a96aa3bSJed Brown   for (t = flt; t <= llt; t++) {
4161*0a96aa3bSJed Brown     p4est_tree_t     *tree    = &(trees[t]);
4162*0a96aa3bSJed Brown     const double     *v       = pforest->topo->conn->vertices;
4163*0a96aa3bSJed Brown     p4est_quadrant_t *quads   = (p4est_quadrant_t*) tree->quadrants.array;
4164*0a96aa3bSJed Brown     PetscInt         offset   = cLocalStart + tree->quadrants_offset;
4165*0a96aa3bSJed Brown     PetscInt         numQuads = (PetscInt) tree->quadrants.elem_count;
4166*0a96aa3bSJed Brown     p4est_topidx_t   vt[8]    = {0,0,0,0,0,0,0,0};
4167*0a96aa3bSJed Brown     PetscInt         i,k;
4168*0a96aa3bSJed Brown 
4169*0a96aa3bSJed Brown     if (!numQuads) continue;
4170*0a96aa3bSJed Brown     for (k = 0; k < P4EST_CHILDREN; ++k) {
4171*0a96aa3bSJed Brown       vt[k] = pforest->topo->conn->tree_to_vertex[t * P4EST_CHILDREN + k];
4172*0a96aa3bSJed Brown     }
4173*0a96aa3bSJed Brown 
4174*0a96aa3bSJed Brown     for (i = 0; i < numQuads; i++) {
4175*0a96aa3bSJed Brown       p4est_quadrant_t  *quad = &quads[i];
4176*0a96aa3bSJed Brown       const PetscReal   intsize = 1.0 / P4EST_ROOT_LEN;
4177*0a96aa3bSJed Brown       PetscReal         h2;
4178*0a96aa3bSJed Brown       PetscScalar       xyz[3];
4179*0a96aa3bSJed Brown #ifdef P4_TO_P8
4180*0a96aa3bSJed Brown       PetscInt          zi;
4181*0a96aa3bSJed Brown #endif
4182*0a96aa3bSJed Brown       PetscInt          yi,xi;
4183*0a96aa3bSJed Brown       PetscInt          off2;
4184*0a96aa3bSJed Brown       PetscInt          newCell = i + offset;
4185*0a96aa3bSJed Brown 
4186*0a96aa3bSJed Brown       ierr = PetscSectionGetFieldDof(newSection, newCell, 0, &cdof);CHKERRQ(ierr);
4187*0a96aa3bSJed Brown       if (!cdof) continue;
4188*0a96aa3bSJed Brown 
4189*0a96aa3bSJed Brown       h2   = .5 * intsize * P4EST_QUADRANT_LEN (quad->level);
4190*0a96aa3bSJed Brown       k    = 0;
4191*0a96aa3bSJed Brown       ierr = PetscSectionGetOffset(newSection, newCell, &off2);CHKERRQ(ierr);
4192*0a96aa3bSJed Brown #ifdef P4_TO_P8
4193*0a96aa3bSJed Brown       for (zi = 0; zi < 2; ++zi) {
4194*0a96aa3bSJed Brown         const PetscReal eta_z = intsize * quad->z + h2 * (1. + (zi * 2 - 1));
4195*0a96aa3bSJed Brown #else
4196*0a96aa3bSJed Brown       {
4197*0a96aa3bSJed Brown         const PetscReal eta_z = 0.0;
4198*0a96aa3bSJed Brown #endif
4199*0a96aa3bSJed Brown         for (yi = 0; yi < 2; ++yi) {
4200*0a96aa3bSJed Brown           const PetscReal eta_y = intsize * quad->y + h2 * (1. + (yi * 2 - 1));
4201*0a96aa3bSJed Brown           for (xi = 0; xi < 2; ++xi) {
4202*0a96aa3bSJed Brown             const PetscReal eta_x = intsize * quad->x + h2 * (1. + (xi * 2 - 1));
4203*0a96aa3bSJed Brown             PetscInt    j;
4204*0a96aa3bSJed Brown 
4205*0a96aa3bSJed Brown             for (j = 0; j < 3; ++j) {
4206*0a96aa3bSJed Brown               xyz[j] = ((1. - eta_z) * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[0] + j] +
4207*0a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[1] + j]) +
4208*0a96aa3bSJed Brown                                               eta_y  * ((1. - eta_x) * v[3 * vt[2] + j] +
4209*0a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[3] + j]))
4210*0a96aa3bSJed Brown                         +     eta_z  * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[4] + j] +
4211*0a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[5] + j]) +
4212*0a96aa3bSJed Brown                                               eta_y  * ((1. - eta_x) * v[3 * vt[6] + j] +
4213*0a96aa3bSJed Brown                                                               eta_x  * v[3 * vt[7] + j])));
4214*0a96aa3bSJed Brown             }
4215*0a96aa3bSJed Brown             for (j = 0; j < cDim; ++j) coords2[off2 + cDim*P4estVertToPetscVert[k] + j] = xyz[j];
4216*0a96aa3bSJed Brown             ++k;
4217*0a96aa3bSJed Brown           }
4218*0a96aa3bSJed Brown         }
4219*0a96aa3bSJed Brown       }
4220*0a96aa3bSJed Brown     }
4221*0a96aa3bSJed Brown   }
4222*0a96aa3bSJed Brown   ierr = VecRestoreArray(cVec, &coords2);CHKERRQ(ierr);
4223*0a96aa3bSJed Brown   ierr = DMSetCoordinatesLocal(plex, cVec);CHKERRQ(ierr);
4224*0a96aa3bSJed Brown   ierr = VecDestroy(&cVec);CHKERRQ(ierr);
4225*0a96aa3bSJed Brown   ierr = PetscSectionDestroy(&newSection);CHKERRQ(ierr);
4226*0a96aa3bSJed Brown   ierr = PetscSectionDestroy(&oldSection);CHKERRQ(ierr);
4227*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4228*0a96aa3bSJed Brown }
4229*0a96aa3bSJed Brown 
4230*0a96aa3bSJed Brown #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
4231*0a96aa3bSJed Brown static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
4232*0a96aa3bSJed Brown {
4233*0a96aa3bSJed Brown   DM_Forest         *forest;
4234*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
4235*0a96aa3bSJed Brown   PetscErrorCode    ierr;
4236*0a96aa3bSJed Brown 
4237*0a96aa3bSJed Brown   PetscFunctionBegin;
4238*0a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
4239*0a96aa3bSJed Brown   pforest = (DM_Forest_pforest *) forest->data;
4240*0a96aa3bSJed Brown   ierr = PetscSFDestroy(&(pforest->pointAdaptToSelfSF));CHKERRQ(ierr);
4241*0a96aa3bSJed Brown   ierr = PetscSFDestroy(&(pforest->pointSelfToAdaptSF));CHKERRQ(ierr);
4242*0a96aa3bSJed Brown   ierr = PetscFree(pforest->pointAdaptToSelfCids);CHKERRQ(ierr);
4243*0a96aa3bSJed Brown   ierr = PetscFree(pforest->pointSelfToAdaptCids);CHKERRQ(ierr);
4244*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4245*0a96aa3bSJed Brown }
4246*0a96aa3bSJed Brown 
4247*0a96aa3bSJed Brown static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
4248*0a96aa3bSJed Brown {
4249*0a96aa3bSJed Brown   DM_Forest            *forest;
4250*0a96aa3bSJed Brown   DM_Forest_pforest    *pforest;
4251*0a96aa3bSJed Brown   DM                   refTree, newPlex, base;
4252*0a96aa3bSJed Brown   PetscInt             adjDim, adjCodim, coordDim;
4253*0a96aa3bSJed Brown   MPI_Comm             comm;
4254*0a96aa3bSJed Brown   PetscBool            isPforest;
4255*0a96aa3bSJed Brown   PetscInt             dim;
4256*0a96aa3bSJed Brown   PetscInt             overlap;
4257*0a96aa3bSJed Brown   p4est_connect_type_t ctype;
4258*0a96aa3bSJed Brown   p4est_locidx_t       first_local_quad = -1;
4259*0a96aa3bSJed Brown   sc_array_t           *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
4260*0a96aa3bSJed Brown   PetscSection         parentSection;
4261*0a96aa3bSJed Brown   PetscSF              pointSF;
4262*0a96aa3bSJed Brown   size_t               zz, count;
4263*0a96aa3bSJed Brown   PetscInt             pStart, pEnd;
4264*0a96aa3bSJed Brown   DMLabel              ghostLabelBase = NULL;
4265*0a96aa3bSJed Brown   PetscErrorCode       ierr;
4266*0a96aa3bSJed Brown 
4267*0a96aa3bSJed Brown   PetscFunctionBegin;
4268*0a96aa3bSJed Brown 
4269*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4270*0a96aa3bSJed Brown   comm = PetscObjectComm((PetscObject)dm);
4271*0a96aa3bSJed Brown   ierr = PetscObjectTypeCompare((PetscObject)dm,DMPFOREST,&isPforest);CHKERRQ(ierr);
4272*0a96aa3bSJed Brown   if (!isPforest) SETERRQ2(comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPFOREST,((PetscObject)dm)->type_name);
4273*0a96aa3bSJed Brown   ierr = DMGetDimension(dm,&dim);CHKERRQ(ierr);
4274*0a96aa3bSJed Brown   if (dim != P4EST_DIM) SETERRQ2(comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %d",P4EST_DIM,dim);
4275*0a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
4276*0a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
4277*0a96aa3bSJed Brown   ierr    = DMForestGetBaseDM(dm,&base);CHKERRQ(ierr);
4278*0a96aa3bSJed Brown   if (base) {
4279*0a96aa3bSJed Brown     ierr = DMGetLabel(base,"ghost",&ghostLabelBase);CHKERRQ(ierr);
4280*0a96aa3bSJed Brown   }
4281*0a96aa3bSJed Brown   if (!pforest->plex) {
4282*0a96aa3bSJed Brown     PetscMPIInt size;
4283*0a96aa3bSJed Brown 
4284*0a96aa3bSJed Brown     ierr = MPI_Comm_size(comm,&size);CHKERRMPI(ierr);
4285*0a96aa3bSJed Brown     ierr = DMCreate(comm,&newPlex);CHKERRQ(ierr);
4286*0a96aa3bSJed Brown     ierr = DMSetType(newPlex,DMPLEX);CHKERRQ(ierr);
4287*0a96aa3bSJed Brown     ierr = DMSetMatType(newPlex,dm->mattype);CHKERRQ(ierr);
4288*0a96aa3bSJed Brown     /* share labels */
4289*0a96aa3bSJed Brown     ierr = DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL);CHKERRQ(ierr);
4290*0a96aa3bSJed Brown     ierr = DMForestGetAdjacencyDimension(dm,&adjDim);CHKERRQ(ierr);
4291*0a96aa3bSJed Brown     ierr = DMForestGetAdjacencyCodimension(dm,&adjCodim);CHKERRQ(ierr);
4292*0a96aa3bSJed Brown     ierr = DMGetCoordinateDim(dm,&coordDim);CHKERRQ(ierr);
4293*0a96aa3bSJed Brown     if (adjDim == 0) {
4294*0a96aa3bSJed Brown       ctype = P4EST_CONNECT_FULL;
4295*0a96aa3bSJed Brown     } else if (adjCodim == 1) {
4296*0a96aa3bSJed Brown       ctype = P4EST_CONNECT_FACE;
4297*0a96aa3bSJed Brown #if defined(P4_TO_P8)
4298*0a96aa3bSJed Brown     } else if (adjDim == 1) {
4299*0a96aa3bSJed Brown       ctype = P8EST_CONNECT_EDGE;
4300*0a96aa3bSJed Brown #endif
4301*0a96aa3bSJed Brown     } else {
4302*0a96aa3bSJed Brown       SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Invalid adjacency dimension %d",adjDim);
4303*0a96aa3bSJed Brown     }
4304*0a96aa3bSJed Brown     if (ctype != P4EST_CONNECT_FULL) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Adjacency dimension %D / codimension %D not supported yet",adjDim,adjCodim);
4305*0a96aa3bSJed Brown     ierr = DMForestGetPartitionOverlap(dm,&overlap);CHKERRQ(ierr);
4306*0a96aa3bSJed Brown     ((DM_Plex *) newPlex->data)->overlap = overlap;
4307*0a96aa3bSJed Brown 
4308*0a96aa3bSJed Brown     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
4309*0a96aa3bSJed Brown     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
4310*0a96aa3bSJed Brown     cones             = sc_array_new(sizeof(p4est_locidx_t));
4311*0a96aa3bSJed Brown     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
4312*0a96aa3bSJed Brown     coords            = sc_array_new(3 * sizeof(double));
4313*0a96aa3bSJed Brown     children          = sc_array_new(sizeof(p4est_locidx_t));
4314*0a96aa3bSJed Brown     parents           = sc_array_new(sizeof(p4est_locidx_t));
4315*0a96aa3bSJed Brown     childids          = sc_array_new(sizeof(p4est_locidx_t));
4316*0a96aa3bSJed Brown     leaves            = sc_array_new(sizeof(p4est_locidx_t));
4317*0a96aa3bSJed Brown     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
4318*0a96aa3bSJed Brown 
4319*0a96aa3bSJed 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));
4320*0a96aa3bSJed Brown 
4321*0a96aa3bSJed Brown     pforest->cLocalStart = (PetscInt) first_local_quad;
4322*0a96aa3bSJed Brown     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt) pforest->forest->local_num_quadrants;
4323*0a96aa3bSJed Brown     ierr                 = locidx_to_PetscInt(points_per_dim);CHKERRQ(ierr);
4324*0a96aa3bSJed Brown     ierr                 = locidx_to_PetscInt(cone_sizes);CHKERRQ(ierr);
4325*0a96aa3bSJed Brown     ierr                 = locidx_to_PetscInt(cones);CHKERRQ(ierr);
4326*0a96aa3bSJed Brown     ierr                 = locidx_to_PetscInt(cone_orientations);CHKERRQ(ierr);
4327*0a96aa3bSJed Brown     ierr                 = coords_double_to_PetscScalar(coords, coordDim);CHKERRQ(ierr);
4328*0a96aa3bSJed Brown     ierr                 = locidx_to_PetscInt(children);CHKERRQ(ierr);
4329*0a96aa3bSJed Brown     ierr                 = locidx_to_PetscInt(parents);CHKERRQ(ierr);
4330*0a96aa3bSJed Brown     ierr                 = locidx_to_PetscInt(childids);CHKERRQ(ierr);
4331*0a96aa3bSJed Brown     ierr                 = locidx_to_PetscInt(leaves);CHKERRQ(ierr);
4332*0a96aa3bSJed Brown     ierr                 = locidx_pair_to_PetscSFNode(remotes);CHKERRQ(ierr);
4333*0a96aa3bSJed Brown 
4334*0a96aa3bSJed Brown     ierr  = DMSetDimension(newPlex,P4EST_DIM);CHKERRQ(ierr);
4335*0a96aa3bSJed Brown     ierr  = DMSetCoordinateDim(newPlex,coordDim);CHKERRQ(ierr);
4336*0a96aa3bSJed Brown     ierr  = DMPlexSetMaxProjectionHeight(newPlex,P4EST_DIM - 1);CHKERRQ(ierr);
4337*0a96aa3bSJed Brown     ierr  = DMPlexCreateFromDAG(newPlex,P4EST_DIM,(PetscInt*)points_per_dim->array,(PetscInt*)cone_sizes->array,(PetscInt*)cones->array,(PetscInt*)cone_orientations->array,(PetscScalar*)coords->array);CHKERRQ(ierr);
4338*0a96aa3bSJed Brown     ierr  = DMPlexConvertOldOrientations_Internal(newPlex);CHKERRQ(ierr);
4339*0a96aa3bSJed Brown     ierr  = DMCreateReferenceTree_pforest(comm,&refTree);CHKERRQ(ierr);
4340*0a96aa3bSJed Brown     ierr  = DMPlexSetReferenceTree(newPlex,refTree);CHKERRQ(ierr);
4341*0a96aa3bSJed Brown     ierr  = PetscSectionCreate(comm,&parentSection);CHKERRQ(ierr);
4342*0a96aa3bSJed Brown     ierr  = DMPlexGetChart(newPlex,&pStart,&pEnd);CHKERRQ(ierr);
4343*0a96aa3bSJed Brown     ierr  = PetscSectionSetChart(parentSection,pStart,pEnd);CHKERRQ(ierr);
4344*0a96aa3bSJed Brown     count = children->elem_count;
4345*0a96aa3bSJed Brown     for (zz = 0; zz < count; zz++) {
4346*0a96aa3bSJed Brown       PetscInt child = *((PetscInt*) sc_array_index(children,zz));
4347*0a96aa3bSJed Brown 
4348*0a96aa3bSJed Brown       ierr = PetscSectionSetDof(parentSection,child,1);CHKERRQ(ierr);
4349*0a96aa3bSJed Brown     }
4350*0a96aa3bSJed Brown     ierr = PetscSectionSetUp(parentSection);CHKERRQ(ierr);
4351*0a96aa3bSJed Brown     ierr = DMPlexSetTree(newPlex,parentSection,(PetscInt*)parents->array,(PetscInt*)childids->array);CHKERRQ(ierr);
4352*0a96aa3bSJed Brown     ierr = PetscSectionDestroy(&parentSection);CHKERRQ(ierr);
4353*0a96aa3bSJed Brown     ierr = PetscSFCreate(comm,&pointSF);CHKERRQ(ierr);
4354*0a96aa3bSJed Brown     /*
4355*0a96aa3bSJed Brown        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
4356*0a96aa3bSJed Brown        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
4357*0a96aa3bSJed Brown     */
4358*0a96aa3bSJed Brown     ierr = PetscSFSetGraph(pointSF,pEnd - pStart,(PetscInt)leaves->elem_count,(PetscInt*)leaves->array,PETSC_COPY_VALUES,(PetscSFNode*)remotes->array,PETSC_COPY_VALUES);CHKERRQ(ierr);
4359*0a96aa3bSJed Brown     ierr = DMSetPointSF(newPlex,pointSF);CHKERRQ(ierr);
4360*0a96aa3bSJed Brown     ierr = DMSetPointSF(dm,pointSF);CHKERRQ(ierr);
4361*0a96aa3bSJed Brown     {
4362*0a96aa3bSJed Brown       DM coordDM;
4363*0a96aa3bSJed Brown 
4364*0a96aa3bSJed Brown       ierr = DMGetCoordinateDM(newPlex,&coordDM);CHKERRQ(ierr);
4365*0a96aa3bSJed Brown       ierr = DMSetPointSF(coordDM,pointSF);CHKERRQ(ierr);
4366*0a96aa3bSJed Brown     }
4367*0a96aa3bSJed Brown     ierr = PetscSFDestroy(&pointSF);CHKERRQ(ierr);
4368*0a96aa3bSJed Brown     sc_array_destroy (points_per_dim);
4369*0a96aa3bSJed Brown     sc_array_destroy (cone_sizes);
4370*0a96aa3bSJed Brown     sc_array_destroy (cones);
4371*0a96aa3bSJed Brown     sc_array_destroy (cone_orientations);
4372*0a96aa3bSJed Brown     sc_array_destroy (coords);
4373*0a96aa3bSJed Brown     sc_array_destroy (children);
4374*0a96aa3bSJed Brown     sc_array_destroy (parents);
4375*0a96aa3bSJed Brown     sc_array_destroy (childids);
4376*0a96aa3bSJed Brown     sc_array_destroy (leaves);
4377*0a96aa3bSJed Brown     sc_array_destroy (remotes);
4378*0a96aa3bSJed Brown 
4379*0a96aa3bSJed Brown     {
4380*0a96aa3bSJed Brown       PetscBool             isper;
4381*0a96aa3bSJed Brown       const PetscReal      *maxCell, *L;
4382*0a96aa3bSJed Brown       const DMBoundaryType *bd;
4383*0a96aa3bSJed Brown 
4384*0a96aa3bSJed Brown       ierr = DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd);CHKERRQ(ierr);
4385*0a96aa3bSJed Brown       ierr = DMSetPeriodicity(newPlex,isper,maxCell,L,bd);CHKERRQ(ierr);
4386*0a96aa3bSJed Brown       ierr = DMPforestLocalizeCoordinates(dm,newPlex);CHKERRQ(ierr);
4387*0a96aa3bSJed Brown     }
4388*0a96aa3bSJed Brown 
4389*0a96aa3bSJed Brown     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
4390*0a96aa3bSJed Brown       Vec               coordsGlobal, coordsLocal;
4391*0a96aa3bSJed Brown       const PetscScalar *globalArray;
4392*0a96aa3bSJed Brown       PetscScalar       *localArray;
4393*0a96aa3bSJed Brown       PetscSF           coordSF;
4394*0a96aa3bSJed Brown       DM                coordDM;
4395*0a96aa3bSJed Brown 
4396*0a96aa3bSJed Brown       ierr = DMGetCoordinateDM(newPlex,&coordDM);CHKERRQ(ierr);
4397*0a96aa3bSJed Brown       ierr = DMGetSectionSF(coordDM,&coordSF);CHKERRQ(ierr);
4398*0a96aa3bSJed Brown       ierr = DMGetCoordinates(newPlex, &coordsGlobal);CHKERRQ(ierr);
4399*0a96aa3bSJed Brown       ierr = DMGetCoordinatesLocal(newPlex, &coordsLocal);CHKERRQ(ierr);
4400*0a96aa3bSJed Brown       ierr = VecGetArrayRead(coordsGlobal, &globalArray);CHKERRQ(ierr);
4401*0a96aa3bSJed Brown       ierr = VecGetArray(coordsLocal, &localArray);CHKERRQ(ierr);
4402*0a96aa3bSJed Brown       ierr = PetscSFBcastBegin(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE);CHKERRQ(ierr);
4403*0a96aa3bSJed Brown       ierr = PetscSFBcastEnd(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE);CHKERRQ(ierr);
4404*0a96aa3bSJed Brown       ierr = VecRestoreArray(coordsLocal, &localArray);CHKERRQ(ierr);
4405*0a96aa3bSJed Brown       ierr = VecRestoreArrayRead(coordsGlobal, &globalArray);CHKERRQ(ierr);
4406*0a96aa3bSJed Brown       ierr = DMSetCoordinatesLocal(newPlex, coordsLocal);CHKERRQ(ierr);
4407*0a96aa3bSJed Brown     }
4408*0a96aa3bSJed Brown     ierr = DMPforestMapCoordinates(dm,newPlex);CHKERRQ(ierr);
4409*0a96aa3bSJed Brown 
4410*0a96aa3bSJed Brown     pforest->plex = newPlex;
4411*0a96aa3bSJed Brown 
4412*0a96aa3bSJed Brown     /* copy labels */
4413*0a96aa3bSJed Brown     ierr = DMPforestLabelsFinalize(dm,newPlex);CHKERRQ(ierr);
4414*0a96aa3bSJed Brown 
4415*0a96aa3bSJed Brown     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
4416*0a96aa3bSJed Brown       PetscInt numAdded;
4417*0a96aa3bSJed Brown       DM       newPlexGhosted;
4418*0a96aa3bSJed Brown       void     *ctx;
4419*0a96aa3bSJed Brown 
4420*0a96aa3bSJed Brown       ierr = DMPlexConstructGhostCells(newPlex,pforest->ghostName,&numAdded,&newPlexGhosted);CHKERRQ(ierr);
4421*0a96aa3bSJed Brown       ierr = DMGetApplicationContext(newPlex,&ctx);CHKERRQ(ierr);
4422*0a96aa3bSJed Brown       ierr = DMSetApplicationContext(newPlexGhosted,ctx);CHKERRQ(ierr);
4423*0a96aa3bSJed Brown       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
4424*0a96aa3bSJed Brown       ierr    = DMGetPointSF(newPlexGhosted,&pointSF);CHKERRQ(ierr);
4425*0a96aa3bSJed Brown       ierr    = DMSetPointSF(dm,pointSF);CHKERRQ(ierr);
4426*0a96aa3bSJed Brown       ierr    = DMDestroy(&newPlex);CHKERRQ(ierr);
4427*0a96aa3bSJed Brown       ierr    = DMPlexSetReferenceTree(newPlexGhosted,refTree);CHKERRQ(ierr);
4428*0a96aa3bSJed Brown       ierr    = DMForestClearAdaptivityForest_pforest(dm);CHKERRQ(ierr);
4429*0a96aa3bSJed Brown       newPlex = newPlexGhosted;
4430*0a96aa3bSJed Brown 
4431*0a96aa3bSJed Brown       /* share the labels back */
4432*0a96aa3bSJed Brown       ierr = DMDestroyLabelLinkList_Internal(dm);CHKERRQ(ierr);
4433*0a96aa3bSJed Brown       ierr = DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL);CHKERRQ(ierr);
4434*0a96aa3bSJed Brown       pforest->plex = newPlex;
4435*0a96aa3bSJed Brown     }
4436*0a96aa3bSJed Brown     ierr = DMDestroy(&refTree);CHKERRQ(ierr);
4437*0a96aa3bSJed Brown     if (dm->setfromoptionscalled) {
4438*0a96aa3bSJed Brown       ierr = PetscObjectOptionsBegin((PetscObject)newPlex);CHKERRQ(ierr);
4439*0a96aa3bSJed Brown       ierr = DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject,newPlex);CHKERRQ(ierr);
4440*0a96aa3bSJed Brown       ierr = PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject) newPlex);CHKERRQ(ierr);
4441*0a96aa3bSJed Brown       ierr = PetscOptionsEnd();CHKERRQ(ierr);
4442*0a96aa3bSJed Brown     }
4443*0a96aa3bSJed Brown     ierr = DMViewFromOptions(newPlex,NULL,"-dm_p4est_plex_view");CHKERRQ(ierr);
4444*0a96aa3bSJed Brown     {
4445*0a96aa3bSJed Brown       PetscSection coordsSec;
4446*0a96aa3bSJed Brown       Vec          coords;
4447*0a96aa3bSJed Brown       PetscInt     cDim;
4448*0a96aa3bSJed Brown 
4449*0a96aa3bSJed Brown       ierr = DMGetCoordinateDim(newPlex,&cDim);CHKERRQ(ierr);
4450*0a96aa3bSJed Brown       ierr = DMGetCoordinateSection(newPlex,&coordsSec);CHKERRQ(ierr);
4451*0a96aa3bSJed Brown       ierr = DMSetCoordinateSection(dm,cDim,coordsSec);CHKERRQ(ierr);
4452*0a96aa3bSJed Brown       ierr = DMGetCoordinatesLocal(newPlex,&coords);CHKERRQ(ierr);
4453*0a96aa3bSJed Brown       ierr = DMSetCoordinatesLocal(dm,coords);CHKERRQ(ierr);
4454*0a96aa3bSJed Brown     }
4455*0a96aa3bSJed Brown   }
4456*0a96aa3bSJed Brown   newPlex = pforest->plex;
4457*0a96aa3bSJed Brown   if (plex) {
4458*0a96aa3bSJed Brown     DM coordDM;
4459*0a96aa3bSJed Brown 
4460*0a96aa3bSJed Brown     ierr = DMClone(newPlex,plex);CHKERRQ(ierr);
4461*0a96aa3bSJed Brown     ierr = DMGetCoordinateDM(newPlex,&coordDM);CHKERRQ(ierr);
4462*0a96aa3bSJed Brown     ierr = DMSetCoordinateDM(*plex,coordDM);CHKERRQ(ierr);
4463*0a96aa3bSJed Brown     ierr = DMShareDiscretization(dm,*plex);CHKERRQ(ierr);
4464*0a96aa3bSJed Brown   }
4465*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4466*0a96aa3bSJed Brown }
4467*0a96aa3bSJed Brown 
4468*0a96aa3bSJed Brown static PetscErrorCode DMSetFromOptions_pforest(PetscOptionItems *PetscOptionsObject,DM dm)
4469*0a96aa3bSJed Brown {
4470*0a96aa3bSJed Brown   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4471*0a96aa3bSJed Brown   char              stringBuffer[256];
4472*0a96aa3bSJed Brown   PetscBool         flg;
4473*0a96aa3bSJed Brown   PetscErrorCode    ierr;
4474*0a96aa3bSJed Brown 
4475*0a96aa3bSJed Brown   PetscFunctionBegin;
4476*0a96aa3bSJed Brown   ierr = DMSetFromOptions_Forest(PetscOptionsObject,dm);CHKERRQ(ierr);
4477*0a96aa3bSJed Brown   ierr = PetscOptionsHead(PetscOptionsObject,"DM" P4EST_STRING " options");CHKERRQ(ierr);
4478*0a96aa3bSJed Brown   ierr = PetscOptionsBool("-dm_p4est_partition_for_coarsening","partition forest to allow for coarsening","DMP4estSetPartitionForCoarsening",pforest->partition_for_coarsening,&(pforest->partition_for_coarsening),NULL);CHKERRQ(ierr);
4479*0a96aa3bSJed Brown   ierr = PetscOptionsString("-dm_p4est_ghost_label_name","the name of the ghost label when converting from a DMPlex",NULL,NULL,stringBuffer,sizeof(stringBuffer),&flg);CHKERRQ(ierr);
4480*0a96aa3bSJed Brown   ierr = PetscOptionsTail();CHKERRQ(ierr);
4481*0a96aa3bSJed Brown   if (flg) {
4482*0a96aa3bSJed Brown     ierr = PetscFree(pforest->ghostName);CHKERRQ(ierr);
4483*0a96aa3bSJed Brown     ierr = PetscStrallocpy(stringBuffer,&pforest->ghostName);CHKERRQ(ierr);
4484*0a96aa3bSJed Brown   }
4485*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4486*0a96aa3bSJed Brown }
4487*0a96aa3bSJed Brown 
4488*0a96aa3bSJed Brown #if !defined(P4_TO_P8)
4489*0a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
4490*0a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
4491*0a96aa3bSJed Brown #else
4492*0a96aa3bSJed Brown #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
4493*0a96aa3bSJed Brown #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
4494*0a96aa3bSJed Brown #endif
4495*0a96aa3bSJed Brown 
4496*0a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
4497*0a96aa3bSJed Brown {
4498*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
4499*0a96aa3bSJed Brown 
4500*0a96aa3bSJed Brown   PetscFunctionBegin;
4501*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4502*0a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4503*0a96aa3bSJed Brown   *flg    = pforest->partition_for_coarsening;
4504*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4505*0a96aa3bSJed Brown }
4506*0a96aa3bSJed Brown 
4507*0a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
4508*0a96aa3bSJed Brown {
4509*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
4510*0a96aa3bSJed Brown 
4511*0a96aa3bSJed Brown   PetscFunctionBegin;
4512*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4513*0a96aa3bSJed Brown   pforest                           = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4514*0a96aa3bSJed Brown   pforest->partition_for_coarsening = flg;
4515*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4516*0a96aa3bSJed Brown }
4517*0a96aa3bSJed Brown 
4518*0a96aa3bSJed Brown static PetscErrorCode DMPforestGetPlex(DM dm,DM *plex)
4519*0a96aa3bSJed Brown {
4520*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
4521*0a96aa3bSJed Brown   PetscErrorCode    ierr;
4522*0a96aa3bSJed Brown 
4523*0a96aa3bSJed Brown   PetscFunctionBegin;
4524*0a96aa3bSJed Brown   if (plex) *plex = NULL;
4525*0a96aa3bSJed Brown   ierr    = DMSetUp(dm);CHKERRQ(ierr);
4526*0a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4527*0a96aa3bSJed Brown   if (!pforest->plex) {
4528*0a96aa3bSJed Brown     ierr = DMConvert_pforest_plex(dm,DMPLEX,NULL);CHKERRQ(ierr);
4529*0a96aa3bSJed Brown   }
4530*0a96aa3bSJed Brown   ierr = DMShareDiscretization(dm,pforest->plex);CHKERRQ(ierr);
4531*0a96aa3bSJed Brown   if (plex) *plex = pforest->plex;
4532*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4533*0a96aa3bSJed Brown }
4534*0a96aa3bSJed Brown 
4535*0a96aa3bSJed Brown #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
4536*0a96aa3bSJed Brown static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
4537*0a96aa3bSJed Brown {
4538*0a96aa3bSJed Brown   PetscSection   gsc, gsf;
4539*0a96aa3bSJed Brown   PetscInt       m, n;
4540*0a96aa3bSJed Brown   DM             cdm;
4541*0a96aa3bSJed Brown   PetscErrorCode ierr;
4542*0a96aa3bSJed Brown 
4543*0a96aa3bSJed Brown   PetscFunctionBegin;
4544*0a96aa3bSJed Brown   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
4545*0a96aa3bSJed Brown   ierr = PetscSectionGetConstrainedStorageSize(gsf, &m);CHKERRQ(ierr);
4546*0a96aa3bSJed Brown   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
4547*0a96aa3bSJed Brown   ierr = PetscSectionGetConstrainedStorageSize(gsc, &n);CHKERRQ(ierr);
4548*0a96aa3bSJed Brown 
4549*0a96aa3bSJed Brown   ierr = MatCreate(PetscObjectComm((PetscObject) dmFine), interpolation);CHKERRQ(ierr);
4550*0a96aa3bSJed Brown   ierr = MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4551*0a96aa3bSJed Brown   ierr = MatSetType(*interpolation, MATAIJ);CHKERRQ(ierr);
4552*0a96aa3bSJed Brown 
4553*0a96aa3bSJed Brown   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
4554*0a96aa3bSJed Brown   if (cdm != dmCoarse) SETERRQ(PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only interpolation from coarse DM for now");
4555*0a96aa3bSJed Brown 
4556*0a96aa3bSJed Brown   {
4557*0a96aa3bSJed Brown     DM       plexF, plexC;
4558*0a96aa3bSJed Brown     PetscSF  sf;
4559*0a96aa3bSJed Brown     PetscInt *cids;
4560*0a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
4561*0a96aa3bSJed Brown 
4562*0a96aa3bSJed Brown     ierr = DMPforestGetPlex(dmCoarse,&plexC);CHKERRQ(ierr);
4563*0a96aa3bSJed Brown     ierr = DMPforestGetPlex(dmFine,&plexF);CHKERRQ(ierr);
4564*0a96aa3bSJed Brown     ierr = DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids);CHKERRQ(ierr);
4565*0a96aa3bSJed Brown     ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
4566*0a96aa3bSJed Brown     ierr = DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation);CHKERRQ(ierr);
4567*0a96aa3bSJed Brown     ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
4568*0a96aa3bSJed Brown     ierr = PetscFree(cids);CHKERRQ(ierr);
4569*0a96aa3bSJed Brown   }
4570*0a96aa3bSJed Brown   ierr = MatViewFromOptions(*interpolation, NULL, "-interp_mat_view");CHKERRQ(ierr);
4571*0a96aa3bSJed Brown   /* Use naive scaling */
4572*0a96aa3bSJed Brown   ierr = DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling);CHKERRQ(ierr);
4573*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4574*0a96aa3bSJed Brown }
4575*0a96aa3bSJed Brown 
4576*0a96aa3bSJed Brown #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
4577*0a96aa3bSJed Brown static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
4578*0a96aa3bSJed Brown {
4579*0a96aa3bSJed Brown   PetscSection   gsc, gsf;
4580*0a96aa3bSJed Brown   PetscInt       m, n;
4581*0a96aa3bSJed Brown   DM             cdm;
4582*0a96aa3bSJed Brown   PetscErrorCode ierr;
4583*0a96aa3bSJed Brown 
4584*0a96aa3bSJed Brown   PetscFunctionBegin;
4585*0a96aa3bSJed Brown   ierr = DMGetGlobalSection(dmFine, &gsf);CHKERRQ(ierr);
4586*0a96aa3bSJed Brown   ierr = PetscSectionGetConstrainedStorageSize(gsf, &n);CHKERRQ(ierr);
4587*0a96aa3bSJed Brown   ierr = DMGetGlobalSection(dmCoarse, &gsc);CHKERRQ(ierr);
4588*0a96aa3bSJed Brown   ierr = PetscSectionGetConstrainedStorageSize(gsc, &m);CHKERRQ(ierr);
4589*0a96aa3bSJed Brown 
4590*0a96aa3bSJed Brown   ierr = MatCreate(PetscObjectComm((PetscObject) dmFine), injection);CHKERRQ(ierr);
4591*0a96aa3bSJed Brown   ierr = MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE);CHKERRQ(ierr);
4592*0a96aa3bSJed Brown   ierr = MatSetType(*injection, MATAIJ);CHKERRQ(ierr);
4593*0a96aa3bSJed Brown 
4594*0a96aa3bSJed Brown   ierr = DMGetCoarseDM(dmFine, &cdm);CHKERRQ(ierr);
4595*0a96aa3bSJed Brown   if (cdm != dmCoarse) SETERRQ(PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only injection to coarse DM for now");
4596*0a96aa3bSJed Brown 
4597*0a96aa3bSJed Brown   {
4598*0a96aa3bSJed Brown     DM       plexF, plexC;
4599*0a96aa3bSJed Brown     PetscSF  sf;
4600*0a96aa3bSJed Brown     PetscInt *cids;
4601*0a96aa3bSJed Brown     PetscInt dofPerDim[4] = {1,1,1,1};
4602*0a96aa3bSJed Brown 
4603*0a96aa3bSJed Brown     ierr = DMPforestGetPlex(dmCoarse,&plexC);CHKERRQ(ierr);
4604*0a96aa3bSJed Brown     ierr = DMPforestGetPlex(dmFine,&plexF);CHKERRQ(ierr);
4605*0a96aa3bSJed Brown     ierr = DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids);CHKERRQ(ierr);
4606*0a96aa3bSJed Brown     ierr = PetscSFSetUp(sf);CHKERRQ(ierr);
4607*0a96aa3bSJed Brown     ierr = DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection);CHKERRQ(ierr);
4608*0a96aa3bSJed Brown     ierr = PetscSFDestroy(&sf);CHKERRQ(ierr);
4609*0a96aa3bSJed Brown     ierr = PetscFree(cids);CHKERRQ(ierr);
4610*0a96aa3bSJed Brown   }
4611*0a96aa3bSJed Brown   ierr = MatViewFromOptions(*injection, NULL, "-inject_mat_view");CHKERRQ(ierr);
4612*0a96aa3bSJed Brown   /* Use naive scaling */
4613*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4614*0a96aa3bSJed Brown }
4615*0a96aa3bSJed Brown 
4616*0a96aa3bSJed Brown #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
4617*0a96aa3bSJed Brown static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
4618*0a96aa3bSJed Brown {
4619*0a96aa3bSJed Brown   DM             dmIn, dmVecIn, base, basec, plex, coarseDM;
4620*0a96aa3bSJed Brown   DM             *hierarchy;
4621*0a96aa3bSJed Brown   PetscSF        sfRed = NULL;
4622*0a96aa3bSJed Brown   PetscDS        ds;
4623*0a96aa3bSJed Brown   Vec            vecInLocal, vecOutLocal;
4624*0a96aa3bSJed Brown   DMLabel        subpointMap;
4625*0a96aa3bSJed Brown   PetscInt       minLevel, mh, n_hi, i;
4626*0a96aa3bSJed Brown   PetscBool      hiforest, *hierarchy_forest;
4627*0a96aa3bSJed Brown   PetscErrorCode ierr;
4628*0a96aa3bSJed Brown 
4629*0a96aa3bSJed Brown   PetscFunctionBegin;
4630*0a96aa3bSJed Brown   ierr = VecGetDM(vecIn,&dmVecIn);CHKERRQ(ierr);
4631*0a96aa3bSJed Brown   ierr = DMGetDS(dmVecIn,&ds);CHKERRQ(ierr);
4632*0a96aa3bSJed Brown   if (!ds) SETERRQ(PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Cannot transfer without a PetscDS object");
4633*0a96aa3bSJed Brown   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
4634*0a96aa3bSJed Brown     PetscSection section;
4635*0a96aa3bSJed Brown     PetscInt     Nf;
4636*0a96aa3bSJed Brown 
4637*0a96aa3bSJed Brown     ierr = DMGetLocalSection(dmVecIn,&section);CHKERRQ(ierr);
4638*0a96aa3bSJed Brown     ierr = PetscSectionGetNumFields(section,&Nf);CHKERRQ(ierr);
4639*0a96aa3bSJed Brown     if (Nf > 3) SETERRQ1(PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Number of fields %D are currently not supported! Send an email at petsc-dev@mcs.anl.gov",Nf);
4640*0a96aa3bSJed Brown   }
4641*0a96aa3bSJed Brown   ierr = DMForestGetMinimumRefinement(dm,&minLevel);CHKERRQ(ierr);
4642*0a96aa3bSJed Brown   if (minLevel) SETERRQ1(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Cannot transfer with minimum refinement set to %D. Rerun with DMForestSetMinimumRefinement(dm,0)",minLevel);
4643*0a96aa3bSJed Brown   ierr = DMForestGetBaseDM(dm,&base);CHKERRQ(ierr);
4644*0a96aa3bSJed Brown   if (!base) SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing base DM");
4645*0a96aa3bSJed Brown 
4646*0a96aa3bSJed Brown   ierr = VecSet(vecOut,0.0);CHKERRQ(ierr);
4647*0a96aa3bSJed Brown   if (dmVecIn == base) { /* sequential runs */
4648*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)vecIn);CHKERRQ(ierr);
4649*0a96aa3bSJed Brown   } else {
4650*0a96aa3bSJed Brown     PetscSection secIn, secInRed;
4651*0a96aa3bSJed Brown     Vec          vecInRed, vecInLocal;
4652*0a96aa3bSJed Brown 
4653*0a96aa3bSJed Brown     ierr = PetscObjectQuery((PetscObject)base,"_base_migration_sf",(PetscObject*)&sfRed);CHKERRQ(ierr);
4654*0a96aa3bSJed Brown     if (!sfRed) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_SUP,"Not the DM set with DMForestSetBaseDM()");
4655*0a96aa3bSJed Brown     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn),&secInRed);CHKERRQ(ierr);
4656*0a96aa3bSJed Brown     ierr = VecCreate(PETSC_COMM_SELF,&vecInRed);CHKERRQ(ierr);
4657*0a96aa3bSJed Brown     ierr = DMGetLocalSection(dmVecIn,&secIn);CHKERRQ(ierr);
4658*0a96aa3bSJed Brown     ierr = DMGetLocalVector(dmVecIn,&vecInLocal);CHKERRQ(ierr);
4659*0a96aa3bSJed Brown     ierr = DMGlobalToLocalBegin(dmVecIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4660*0a96aa3bSJed Brown     ierr = DMGlobalToLocalEnd(dmVecIn,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4661*0a96aa3bSJed Brown     ierr = DMPlexDistributeField(dmVecIn,sfRed,secIn,vecInLocal,secInRed,vecInRed);CHKERRQ(ierr);
4662*0a96aa3bSJed Brown     ierr = DMRestoreLocalVector(dmVecIn,&vecInLocal);CHKERRQ(ierr);
4663*0a96aa3bSJed Brown     ierr = PetscSectionDestroy(&secInRed);CHKERRQ(ierr);
4664*0a96aa3bSJed Brown     vecIn = vecInRed;
4665*0a96aa3bSJed Brown   }
4666*0a96aa3bSJed Brown 
4667*0a96aa3bSJed Brown   /* we first search through the AdaptivityForest hierarchy
4668*0a96aa3bSJed Brown      once we found the first disconnected forest, we upsweep the DM hierarchy */
4669*0a96aa3bSJed Brown   hiforest = PETSC_TRUE;
4670*0a96aa3bSJed Brown 
4671*0a96aa3bSJed Brown   /* upsweep to the coarsest DM */
4672*0a96aa3bSJed Brown   n_hi = 0;
4673*0a96aa3bSJed Brown   coarseDM = dm;
4674*0a96aa3bSJed Brown   do {
4675*0a96aa3bSJed Brown     PetscBool isforest;
4676*0a96aa3bSJed Brown 
4677*0a96aa3bSJed Brown     dmIn = coarseDM;
4678*0a96aa3bSJed Brown     /* need to call DMSetUp to have the hierarchy recursively setup */
4679*0a96aa3bSJed Brown     ierr = DMSetUp(dmIn);CHKERRQ(ierr);
4680*0a96aa3bSJed Brown     ierr = DMIsForest(dmIn,&isforest);CHKERRQ(ierr);
4681*0a96aa3bSJed Brown     if (!isforest) SETERRQ1(PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Cannot currently transfer through a mixed hierarchy! Found DM type %s",((PetscObject)dmIn)->type_name);
4682*0a96aa3bSJed Brown     coarseDM = NULL;
4683*0a96aa3bSJed Brown     if (hiforest) {
4684*0a96aa3bSJed Brown       ierr = DMForestGetAdaptivityForest(dmIn,&coarseDM);CHKERRQ(ierr);
4685*0a96aa3bSJed Brown     }
4686*0a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
4687*0a96aa3bSJed Brown       hiforest = PETSC_FALSE;
4688*0a96aa3bSJed Brown       ierr = DMGetCoarseDM(dmIn,&coarseDM);CHKERRQ(ierr);
4689*0a96aa3bSJed Brown     }
4690*0a96aa3bSJed Brown     n_hi++;
4691*0a96aa3bSJed Brown   } while (coarseDM);
4692*0a96aa3bSJed Brown 
4693*0a96aa3bSJed Brown   ierr = PetscMalloc2(n_hi,&hierarchy,n_hi,&hierarchy_forest);CHKERRQ(ierr);
4694*0a96aa3bSJed Brown 
4695*0a96aa3bSJed Brown   i = 0;
4696*0a96aa3bSJed Brown   hiforest = PETSC_TRUE;
4697*0a96aa3bSJed Brown   coarseDM = dm;
4698*0a96aa3bSJed Brown   do {
4699*0a96aa3bSJed Brown     dmIn = coarseDM;
4700*0a96aa3bSJed Brown     coarseDM = NULL;
4701*0a96aa3bSJed Brown     if (hiforest) {
4702*0a96aa3bSJed Brown       ierr = DMForestGetAdaptivityForest(dmIn,&coarseDM);CHKERRQ(ierr);
4703*0a96aa3bSJed Brown     }
4704*0a96aa3bSJed Brown     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
4705*0a96aa3bSJed Brown       hiforest = PETSC_FALSE;
4706*0a96aa3bSJed Brown       ierr = DMGetCoarseDM(dmIn,&coarseDM);CHKERRQ(ierr);
4707*0a96aa3bSJed Brown     }
4708*0a96aa3bSJed Brown     i++;
4709*0a96aa3bSJed Brown     hierarchy[n_hi - i] = dmIn;
4710*0a96aa3bSJed Brown   } while (coarseDM);
4711*0a96aa3bSJed Brown 
4712*0a96aa3bSJed Brown   /* project base vector on the coarsest forest (minimum refinement = 0) */
4713*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dmIn,&plex);CHKERRQ(ierr);
4714*0a96aa3bSJed Brown 
4715*0a96aa3bSJed Brown   /* Check this plex is compatible with the base */
4716*0a96aa3bSJed Brown   {
4717*0a96aa3bSJed Brown     IS       gnum[2];
4718*0a96aa3bSJed Brown     PetscInt ncells[2],gncells[2];
4719*0a96aa3bSJed Brown 
4720*0a96aa3bSJed Brown     ierr = DMPlexGetCellNumbering(base,&gnum[0]);CHKERRQ(ierr);
4721*0a96aa3bSJed Brown     ierr = DMPlexGetCellNumbering(plex,&gnum[1]);CHKERRQ(ierr);
4722*0a96aa3bSJed Brown     ierr = ISGetMinMax(gnum[0],NULL,&ncells[0]);CHKERRQ(ierr);
4723*0a96aa3bSJed Brown     ierr = ISGetMinMax(gnum[1],NULL,&ncells[1]);CHKERRQ(ierr);
4724*0a96aa3bSJed Brown     ierr = MPIU_Allreduce(ncells,gncells,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm));CHKERRMPI(ierr);
4725*0a96aa3bSJed Brown     if (gncells[0] != gncells[1]) SETERRQ2(PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Invalid number of base cells! Expected %D, found %D",gncells[0]+1,gncells[1]+1);
4726*0a96aa3bSJed Brown   }
4727*0a96aa3bSJed Brown 
4728*0a96aa3bSJed Brown   ierr = DMGetLabel(dmIn,"_forest_base_subpoint_map",&subpointMap);CHKERRQ(ierr);
4729*0a96aa3bSJed Brown   if (!subpointMap) SETERRQ(PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing _forest_base_subpoint_map label");
4730*0a96aa3bSJed Brown 
4731*0a96aa3bSJed Brown   ierr = DMPlexGetMaxProjectionHeight(base,&mh);CHKERRQ(ierr);
4732*0a96aa3bSJed Brown   ierr = DMPlexSetMaxProjectionHeight(plex,mh);CHKERRQ(ierr);
4733*0a96aa3bSJed Brown 
4734*0a96aa3bSJed Brown   ierr = DMClone(base,&basec);CHKERRQ(ierr);
4735*0a96aa3bSJed Brown   ierr = DMCopyDisc(dmVecIn,basec);CHKERRQ(ierr);
4736*0a96aa3bSJed Brown   if (sfRed) {
4737*0a96aa3bSJed Brown     ierr = PetscObjectReference((PetscObject)vecIn);CHKERRQ(ierr);
4738*0a96aa3bSJed Brown     vecInLocal = vecIn;
4739*0a96aa3bSJed Brown   } else {
4740*0a96aa3bSJed Brown     ierr = DMCreateLocalVector(basec,&vecInLocal);CHKERRQ(ierr);
4741*0a96aa3bSJed Brown     ierr = DMGlobalToLocalBegin(basec,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4742*0a96aa3bSJed Brown     ierr = DMGlobalToLocalEnd(basec,vecIn,INSERT_VALUES,vecInLocal);CHKERRQ(ierr);
4743*0a96aa3bSJed Brown   }
4744*0a96aa3bSJed Brown 
4745*0a96aa3bSJed Brown   ierr = DMGetLocalVector(dmIn,&vecOutLocal);CHKERRQ(ierr);
4746*0a96aa3bSJed Brown   { /* get degrees of freedom ordered onto dmIn */
4747*0a96aa3bSJed Brown     PetscSF            basetocoarse;
4748*0a96aa3bSJed Brown     PetscInt           bStart, bEnd, nroots;
4749*0a96aa3bSJed Brown     PetscInt           iStart, iEnd, nleaves, leaf;
4750*0a96aa3bSJed Brown     PetscMPIInt        rank;
4751*0a96aa3bSJed Brown     PetscSFNode       *remotes;
4752*0a96aa3bSJed Brown     PetscSection       secIn, secOut;
4753*0a96aa3bSJed Brown     PetscInt          *remoteOffsets;
4754*0a96aa3bSJed Brown     PetscSF            transferSF;
4755*0a96aa3bSJed Brown     const PetscScalar *inArray;
4756*0a96aa3bSJed Brown     PetscScalar       *outArray;
4757*0a96aa3bSJed Brown 
4758*0a96aa3bSJed Brown     ierr = MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank);CHKERRMPI(ierr);
4759*0a96aa3bSJed Brown     ierr = DMPlexGetChart(basec, &bStart, &bEnd);CHKERRQ(ierr);
4760*0a96aa3bSJed Brown     nroots = PetscMax(bEnd - bStart, 0);
4761*0a96aa3bSJed Brown     ierr = DMPlexGetChart(plex, &iStart, &iEnd);CHKERRQ(ierr);
4762*0a96aa3bSJed Brown     nleaves = PetscMax(iEnd - iStart, 0);
4763*0a96aa3bSJed Brown 
4764*0a96aa3bSJed Brown     ierr = PetscMalloc1(nleaves, &remotes);CHKERRQ(ierr);
4765*0a96aa3bSJed Brown     for (leaf = iStart; leaf < iEnd; leaf++) {
4766*0a96aa3bSJed Brown       PetscInt index;
4767*0a96aa3bSJed Brown 
4768*0a96aa3bSJed Brown       remotes[leaf - iStart].rank = rank;
4769*0a96aa3bSJed Brown       ierr = DMLabelGetValue(subpointMap, leaf, &index);CHKERRQ(ierr);
4770*0a96aa3bSJed Brown       remotes[leaf - iStart].index = index;
4771*0a96aa3bSJed Brown     }
4772*0a96aa3bSJed Brown 
4773*0a96aa3bSJed Brown     ierr = PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse);CHKERRQ(ierr);
4774*0a96aa3bSJed Brown     ierr = PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER);CHKERRQ(ierr);
4775*0a96aa3bSJed Brown     ierr = PetscSFSetUp(basetocoarse);CHKERRQ(ierr);
4776*0a96aa3bSJed Brown     ierr = DMGetLocalSection(basec,&secIn);CHKERRQ(ierr);
4777*0a96aa3bSJed Brown     ierr = PetscSectionCreate(PetscObjectComm((PetscObject)dmIn),&secOut);CHKERRQ(ierr);
4778*0a96aa3bSJed Brown     ierr = PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut);CHKERRQ(ierr);
4779*0a96aa3bSJed Brown     ierr = PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF);CHKERRQ(ierr);
4780*0a96aa3bSJed Brown     ierr = PetscFree(remoteOffsets);CHKERRQ(ierr);
4781*0a96aa3bSJed Brown     ierr = VecGetArrayWrite(vecOutLocal, &outArray);CHKERRQ(ierr);
4782*0a96aa3bSJed Brown     ierr = VecGetArrayRead(vecInLocal, &inArray);CHKERRQ(ierr);
4783*0a96aa3bSJed Brown     ierr = PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE);CHKERRQ(ierr);
4784*0a96aa3bSJed Brown     ierr = PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE);CHKERRQ(ierr);
4785*0a96aa3bSJed Brown     ierr = VecRestoreArrayRead(vecInLocal, &inArray);CHKERRQ(ierr);
4786*0a96aa3bSJed Brown     ierr = VecRestoreArrayWrite(vecOutLocal, &outArray);CHKERRQ(ierr);
4787*0a96aa3bSJed Brown     ierr = PetscSFDestroy(&transferSF);CHKERRQ(ierr);
4788*0a96aa3bSJed Brown     ierr = PetscSectionDestroy(&secOut);CHKERRQ(ierr);
4789*0a96aa3bSJed Brown     ierr = PetscSFDestroy(&basetocoarse);CHKERRQ(ierr);
4790*0a96aa3bSJed Brown   }
4791*0a96aa3bSJed Brown   ierr = VecDestroy(&vecInLocal);CHKERRQ(ierr);
4792*0a96aa3bSJed Brown   ierr = DMDestroy(&basec);CHKERRQ(ierr);
4793*0a96aa3bSJed Brown   ierr = VecDestroy(&vecIn);CHKERRQ(ierr);
4794*0a96aa3bSJed Brown 
4795*0a96aa3bSJed Brown   /* output */
4796*0a96aa3bSJed Brown   if (n_hi > 1) { /* downsweep the stored hierarchy */
4797*0a96aa3bSJed Brown     Vec vecOut1, vecOut2;
4798*0a96aa3bSJed Brown     DM  fineDM;
4799*0a96aa3bSJed Brown 
4800*0a96aa3bSJed Brown     ierr = DMGetGlobalVector(dmIn,&vecOut1);CHKERRQ(ierr);
4801*0a96aa3bSJed Brown     ierr = DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut1);CHKERRQ(ierr);
4802*0a96aa3bSJed Brown     ierr = DMRestoreLocalVector(dmIn,&vecOutLocal);CHKERRQ(ierr);
4803*0a96aa3bSJed Brown     for (i = 1; i < n_hi-1; i++) {
4804*0a96aa3bSJed Brown       fineDM  = hierarchy[i];
4805*0a96aa3bSJed Brown       ierr    = DMGetGlobalVector(fineDM,&vecOut2);CHKERRQ(ierr);
4806*0a96aa3bSJed Brown       ierr    = DMForestTransferVec(dmIn,vecOut1,fineDM,vecOut2,PETSC_TRUE,0.0);CHKERRQ(ierr);
4807*0a96aa3bSJed Brown       ierr    = DMRestoreGlobalVector(dmIn,&vecOut1);CHKERRQ(ierr);
4808*0a96aa3bSJed Brown       vecOut1 = vecOut2;
4809*0a96aa3bSJed Brown       dmIn    = fineDM;
4810*0a96aa3bSJed Brown     }
4811*0a96aa3bSJed Brown     ierr = DMForestTransferVec(dmIn,vecOut1,dm,vecOut,PETSC_TRUE,0.0);CHKERRQ(ierr);
4812*0a96aa3bSJed Brown     ierr = DMRestoreGlobalVector(dmIn,&vecOut1);CHKERRQ(ierr);
4813*0a96aa3bSJed Brown   } else {
4814*0a96aa3bSJed Brown     ierr = DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut);CHKERRQ(ierr);
4815*0a96aa3bSJed Brown     ierr = DMRestoreLocalVector(dmIn,&vecOutLocal);CHKERRQ(ierr);
4816*0a96aa3bSJed Brown   }
4817*0a96aa3bSJed Brown   ierr = PetscFree2(hierarchy,hierarchy_forest);CHKERRQ(ierr);
4818*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4819*0a96aa3bSJed Brown }
4820*0a96aa3bSJed Brown 
4821*0a96aa3bSJed Brown #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
4822*0a96aa3bSJed Brown static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
4823*0a96aa3bSJed Brown {
4824*0a96aa3bSJed Brown   DM             adaptIn, adaptOut, plexIn, plexOut;
4825*0a96aa3bSJed Brown   DM_Forest      *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
4826*0a96aa3bSJed Brown   PetscInt       dofPerDim[] = {1, 1, 1, 1};
4827*0a96aa3bSJed Brown   PetscSF        inSF = NULL, outSF = NULL;
4828*0a96aa3bSJed Brown   PetscInt       *inCids = NULL, *outCids = NULL;
4829*0a96aa3bSJed Brown   DMAdaptFlag    purposeIn, purposeOut;
4830*0a96aa3bSJed Brown   PetscErrorCode ierr;
4831*0a96aa3bSJed Brown 
4832*0a96aa3bSJed Brown   PetscFunctionBegin;
4833*0a96aa3bSJed Brown   forestOut = (DM_Forest *) dmOut->data;
4834*0a96aa3bSJed Brown   forestIn  = (DM_Forest *) dmIn->data;
4835*0a96aa3bSJed Brown 
4836*0a96aa3bSJed Brown   ierr = DMForestGetAdaptivityForest(dmOut,&adaptOut);CHKERRQ(ierr);
4837*0a96aa3bSJed Brown   ierr = DMForestGetAdaptivityPurpose(dmOut,&purposeOut);CHKERRQ(ierr);
4838*0a96aa3bSJed Brown   forestAdaptOut = adaptOut ? (DM_Forest *) adaptOut->data : NULL;
4839*0a96aa3bSJed Brown 
4840*0a96aa3bSJed Brown   ierr = DMForestGetAdaptivityForest(dmIn,&adaptIn);CHKERRQ(ierr);
4841*0a96aa3bSJed Brown   ierr = DMForestGetAdaptivityPurpose(dmIn,&purposeIn);CHKERRQ(ierr);
4842*0a96aa3bSJed Brown   forestAdaptIn  = adaptIn ? (DM_Forest *) adaptIn->data : NULL;
4843*0a96aa3bSJed Brown 
4844*0a96aa3bSJed Brown   if (forestAdaptOut == forestIn) {
4845*0a96aa3bSJed Brown     switch (purposeOut) {
4846*0a96aa3bSJed Brown     case DM_ADAPT_REFINE:
4847*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids);CHKERRQ(ierr);
4848*0a96aa3bSJed Brown       ierr = PetscSFSetUp(inSF);CHKERRQ(ierr);
4849*0a96aa3bSJed Brown       break;
4850*0a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
4851*0a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
4852*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&outCids);CHKERRQ(ierr);
4853*0a96aa3bSJed Brown       ierr = PetscSFSetUp(outSF);CHKERRQ(ierr);
4854*0a96aa3bSJed Brown       break;
4855*0a96aa3bSJed Brown     default:
4856*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids);CHKERRQ(ierr);
4857*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids);CHKERRQ(ierr);
4858*0a96aa3bSJed Brown       ierr = PetscSFSetUp(inSF);CHKERRQ(ierr);
4859*0a96aa3bSJed Brown       ierr = PetscSFSetUp(outSF);CHKERRQ(ierr);
4860*0a96aa3bSJed Brown     }
4861*0a96aa3bSJed Brown   } else if (forestAdaptIn == forestOut) {
4862*0a96aa3bSJed Brown     switch (purposeIn) {
4863*0a96aa3bSJed Brown     case DM_ADAPT_REFINE:
4864*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&inCids);CHKERRQ(ierr);
4865*0a96aa3bSJed Brown       ierr = PetscSFSetUp(outSF);CHKERRQ(ierr);
4866*0a96aa3bSJed Brown       break;
4867*0a96aa3bSJed Brown     case DM_ADAPT_COARSEN:
4868*0a96aa3bSJed Brown     case DM_ADAPT_COARSEN_LAST:
4869*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids);CHKERRQ(ierr);
4870*0a96aa3bSJed Brown       ierr = PetscSFSetUp(inSF);CHKERRQ(ierr);
4871*0a96aa3bSJed Brown       break;
4872*0a96aa3bSJed Brown     default:
4873*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids);CHKERRQ(ierr);
4874*0a96aa3bSJed Brown       ierr = DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids);CHKERRQ(ierr);
4875*0a96aa3bSJed Brown       ierr = PetscSFSetUp(inSF);CHKERRQ(ierr);
4876*0a96aa3bSJed Brown       ierr = PetscSFSetUp(outSF);CHKERRQ(ierr);
4877*0a96aa3bSJed Brown     }
4878*0a96aa3bSJed Brown   } else SETERRQ(PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Only support transfer from pre-adaptivity to post-adaptivity right now");
4879*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dmIn,&plexIn);CHKERRQ(ierr);
4880*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dmOut,&plexOut);CHKERRQ(ierr);
4881*0a96aa3bSJed Brown 
4882*0a96aa3bSJed Brown   ierr = DMPlexTransferVecTree(plexIn,vecIn,plexOut,vecOut,inSF,outSF,inCids,outCids,useBCs,time);CHKERRQ(ierr);
4883*0a96aa3bSJed Brown   ierr = PetscFree(inCids);CHKERRQ(ierr);
4884*0a96aa3bSJed Brown   ierr = PetscFree(outCids);CHKERRQ(ierr);
4885*0a96aa3bSJed Brown   ierr = PetscSFDestroy(&inSF);CHKERRQ(ierr);
4886*0a96aa3bSJed Brown   ierr = PetscSFDestroy(&outSF);CHKERRQ(ierr);
4887*0a96aa3bSJed Brown   ierr = PetscFree(inCids);CHKERRQ(ierr);
4888*0a96aa3bSJed Brown   ierr = PetscFree(outCids);CHKERRQ(ierr);
4889*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4890*0a96aa3bSJed Brown }
4891*0a96aa3bSJed Brown 
4892*0a96aa3bSJed Brown #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
4893*0a96aa3bSJed Brown static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm,DM *cdm)
4894*0a96aa3bSJed Brown {
4895*0a96aa3bSJed Brown   DM             plex;
4896*0a96aa3bSJed Brown   PetscErrorCode ierr;
4897*0a96aa3bSJed Brown 
4898*0a96aa3bSJed Brown   PetscFunctionBegin;
4899*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4900*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
4901*0a96aa3bSJed Brown   ierr = DMGetCoordinateDM(plex,cdm);CHKERRQ(ierr);
4902*0a96aa3bSJed Brown   ierr = PetscObjectReference((PetscObject)*cdm);CHKERRQ(ierr);
4903*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4904*0a96aa3bSJed Brown }
4905*0a96aa3bSJed Brown 
4906*0a96aa3bSJed Brown #define VecViewLocal_pforest _append_pforest(VecViewLocal)
4907*0a96aa3bSJed Brown static PetscErrorCode VecViewLocal_pforest(Vec vec,PetscViewer viewer)
4908*0a96aa3bSJed Brown {
4909*0a96aa3bSJed Brown   DM             dm, plex;
4910*0a96aa3bSJed Brown   PetscErrorCode ierr;
4911*0a96aa3bSJed Brown 
4912*0a96aa3bSJed Brown   PetscFunctionBegin;
4913*0a96aa3bSJed Brown   ierr = VecGetDM(vec,&dm);CHKERRQ(ierr);
4914*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
4915*0a96aa3bSJed Brown   ierr = VecSetDM(vec,plex);CHKERRQ(ierr);
4916*0a96aa3bSJed Brown   ierr = VecView_Plex_Local(vec,viewer);CHKERRQ(ierr);
4917*0a96aa3bSJed Brown   ierr = VecSetDM(vec,dm);CHKERRQ(ierr);
4918*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4919*0a96aa3bSJed Brown }
4920*0a96aa3bSJed Brown 
4921*0a96aa3bSJed Brown #define VecView_pforest _append_pforest(VecView)
4922*0a96aa3bSJed Brown static PetscErrorCode VecView_pforest(Vec vec,PetscViewer viewer)
4923*0a96aa3bSJed Brown {
4924*0a96aa3bSJed Brown   DM             dm, plex;
4925*0a96aa3bSJed Brown   PetscErrorCode ierr;
4926*0a96aa3bSJed Brown 
4927*0a96aa3bSJed Brown   PetscFunctionBegin;
4928*0a96aa3bSJed Brown   ierr = VecGetDM(vec,&dm);CHKERRQ(ierr);
4929*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
4930*0a96aa3bSJed Brown   ierr = VecSetDM(vec,plex);CHKERRQ(ierr);
4931*0a96aa3bSJed Brown   ierr = VecView_Plex(vec,viewer);CHKERRQ(ierr);
4932*0a96aa3bSJed Brown   ierr = VecSetDM(vec,dm);CHKERRQ(ierr);
4933*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4934*0a96aa3bSJed Brown }
4935*0a96aa3bSJed Brown 
4936*0a96aa3bSJed Brown #define VecView_pforest_Native _infix_pforest(VecView,_Native)
4937*0a96aa3bSJed Brown static PetscErrorCode VecView_pforest_Native(Vec vec,PetscViewer viewer)
4938*0a96aa3bSJed Brown {
4939*0a96aa3bSJed Brown   DM             dm, plex;
4940*0a96aa3bSJed Brown   PetscErrorCode ierr;
4941*0a96aa3bSJed Brown 
4942*0a96aa3bSJed Brown   PetscFunctionBegin;
4943*0a96aa3bSJed Brown   ierr = VecGetDM(vec,&dm);CHKERRQ(ierr);
4944*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
4945*0a96aa3bSJed Brown   ierr = VecSetDM(vec,plex);CHKERRQ(ierr);
4946*0a96aa3bSJed Brown   ierr = VecView_Plex_Native(vec,viewer);CHKERRQ(ierr);
4947*0a96aa3bSJed Brown   ierr = VecSetDM(vec,dm);CHKERRQ(ierr);
4948*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4949*0a96aa3bSJed Brown }
4950*0a96aa3bSJed Brown 
4951*0a96aa3bSJed Brown #define VecLoad_pforest _append_pforest(VecLoad)
4952*0a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest(Vec vec,PetscViewer viewer)
4953*0a96aa3bSJed Brown {
4954*0a96aa3bSJed Brown   DM             dm, plex;
4955*0a96aa3bSJed Brown   PetscErrorCode ierr;
4956*0a96aa3bSJed Brown 
4957*0a96aa3bSJed Brown   PetscFunctionBegin;
4958*0a96aa3bSJed Brown   ierr = VecGetDM(vec,&dm);CHKERRQ(ierr);
4959*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
4960*0a96aa3bSJed Brown   ierr = VecSetDM(vec,plex);CHKERRQ(ierr);
4961*0a96aa3bSJed Brown   ierr = VecLoad_Plex(vec,viewer);CHKERRQ(ierr);
4962*0a96aa3bSJed Brown   ierr = VecSetDM(vec,dm);CHKERRQ(ierr);
4963*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4964*0a96aa3bSJed Brown }
4965*0a96aa3bSJed Brown 
4966*0a96aa3bSJed Brown #define VecLoad_pforest_Native _infix_pforest(VecLoad,_Native)
4967*0a96aa3bSJed Brown static PetscErrorCode VecLoad_pforest_Native(Vec vec,PetscViewer viewer)
4968*0a96aa3bSJed Brown {
4969*0a96aa3bSJed Brown   DM             dm, plex;
4970*0a96aa3bSJed Brown   PetscErrorCode ierr;
4971*0a96aa3bSJed Brown 
4972*0a96aa3bSJed Brown   PetscFunctionBegin;
4973*0a96aa3bSJed Brown   ierr = VecGetDM(vec,&dm);CHKERRQ(ierr);
4974*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
4975*0a96aa3bSJed Brown   ierr = VecSetDM(vec,plex);CHKERRQ(ierr);
4976*0a96aa3bSJed Brown   ierr = VecLoad_Plex_Native(vec,viewer);CHKERRQ(ierr);
4977*0a96aa3bSJed Brown   ierr = VecSetDM(vec,dm);CHKERRQ(ierr);
4978*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4979*0a96aa3bSJed Brown }
4980*0a96aa3bSJed Brown 
4981*0a96aa3bSJed Brown #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
4982*0a96aa3bSJed Brown static PetscErrorCode DMCreateGlobalVector_pforest(DM dm,Vec *vec)
4983*0a96aa3bSJed Brown {
4984*0a96aa3bSJed Brown   PetscErrorCode ierr;
4985*0a96aa3bSJed Brown 
4986*0a96aa3bSJed Brown   PetscFunctionBegin;
4987*0a96aa3bSJed Brown   ierr = DMCreateGlobalVector_Section_Private(dm,vec);CHKERRQ(ierr);
4988*0a96aa3bSJed Brown   /* ierr = VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM);CHKERRQ(ierr); */
4989*0a96aa3bSJed Brown   ierr = VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest);CHKERRQ(ierr);
4990*0a96aa3bSJed Brown   ierr = VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native);CHKERRQ(ierr);
4991*0a96aa3bSJed Brown   ierr = VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest);CHKERRQ(ierr);
4992*0a96aa3bSJed Brown   ierr = VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native);CHKERRQ(ierr);
4993*0a96aa3bSJed Brown   PetscFunctionReturn(0);
4994*0a96aa3bSJed Brown }
4995*0a96aa3bSJed Brown 
4996*0a96aa3bSJed Brown #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
4997*0a96aa3bSJed Brown static PetscErrorCode DMCreateLocalVector_pforest(DM dm,Vec *vec)
4998*0a96aa3bSJed Brown {
4999*0a96aa3bSJed Brown   PetscErrorCode ierr;
5000*0a96aa3bSJed Brown 
5001*0a96aa3bSJed Brown   PetscFunctionBegin;
5002*0a96aa3bSJed Brown   ierr = DMCreateLocalVector_Section_Private(dm,vec);CHKERRQ(ierr);
5003*0a96aa3bSJed Brown   ierr = VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest);CHKERRQ(ierr);
5004*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5005*0a96aa3bSJed Brown }
5006*0a96aa3bSJed Brown 
5007*0a96aa3bSJed Brown #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
5008*0a96aa3bSJed Brown static PetscErrorCode DMCreateMatrix_pforest(DM dm,Mat *mat)
5009*0a96aa3bSJed Brown {
5010*0a96aa3bSJed Brown   DM             plex;
5011*0a96aa3bSJed Brown   PetscErrorCode ierr;
5012*0a96aa3bSJed Brown 
5013*0a96aa3bSJed Brown   PetscFunctionBegin;
5014*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5015*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5016*0a96aa3bSJed Brown   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only;  /* maybe this should go into forest->plex */
5017*0a96aa3bSJed Brown   ierr = DMCreateMatrix(plex,mat);CHKERRQ(ierr);
5018*0a96aa3bSJed Brown   ierr = MatSetDM(*mat,dm);CHKERRQ(ierr);
5019*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5020*0a96aa3bSJed Brown }
5021*0a96aa3bSJed Brown 
5022*0a96aa3bSJed Brown #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
5023*0a96aa3bSJed Brown static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, InsertMode mode, Vec localX)
5024*0a96aa3bSJed Brown {
5025*0a96aa3bSJed Brown   DM             plex;
5026*0a96aa3bSJed Brown   PetscErrorCode ierr;
5027*0a96aa3bSJed Brown 
5028*0a96aa3bSJed Brown   PetscFunctionBegin;
5029*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5030*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5031*0a96aa3bSJed Brown   ierr = DMProjectFunctionLocal(plex,time,funcs,ctxs,mode,localX);CHKERRQ(ierr);
5032*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5033*0a96aa3bSJed Brown }
5034*0a96aa3bSJed Brown 
5035*0a96aa3bSJed Brown #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
5036*0a96aa3bSJed 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)
5037*0a96aa3bSJed Brown {
5038*0a96aa3bSJed Brown   DM             plex;
5039*0a96aa3bSJed Brown   PetscErrorCode ierr;
5040*0a96aa3bSJed Brown 
5041*0a96aa3bSJed Brown   PetscFunctionBegin;
5042*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5043*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5044*0a96aa3bSJed Brown   ierr = DMProjectFunctionLabelLocal(plex,time,label,numIds,ids,Ncc,comps,funcs,ctxs,mode,localX);CHKERRQ(ierr);
5045*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5046*0a96aa3bSJed Brown }
5047*0a96aa3bSJed Brown 
5048*0a96aa3bSJed Brown #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
5049*0a96aa3bSJed Brown PetscErrorCode DMProjectFieldLocal_pforest(DM dm, PetscReal time, Vec localU,void (**funcs) (PetscInt, PetscInt, PetscInt,
5050*0a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5051*0a96aa3bSJed Brown                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
5052*0a96aa3bSJed Brown                                                                              PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),InsertMode mode, Vec localX)
5053*0a96aa3bSJed Brown {
5054*0a96aa3bSJed Brown   DM             plex;
5055*0a96aa3bSJed Brown   PetscErrorCode ierr;
5056*0a96aa3bSJed Brown 
5057*0a96aa3bSJed Brown   PetscFunctionBegin;
5058*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5059*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5060*0a96aa3bSJed Brown   ierr = DMProjectFieldLocal(plex,time,localU,funcs,mode,localX);CHKERRQ(ierr);
5061*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5062*0a96aa3bSJed Brown }
5063*0a96aa3bSJed Brown 
5064*0a96aa3bSJed Brown #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
5065*0a96aa3bSJed Brown PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal *diff)
5066*0a96aa3bSJed Brown {
5067*0a96aa3bSJed Brown   DM             plex;
5068*0a96aa3bSJed Brown   PetscErrorCode ierr;
5069*0a96aa3bSJed Brown 
5070*0a96aa3bSJed Brown   PetscFunctionBegin;
5071*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5072*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5073*0a96aa3bSJed Brown   ierr = DMComputeL2Diff(plex,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
5074*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5075*0a96aa3bSJed Brown }
5076*0a96aa3bSJed Brown 
5077*0a96aa3bSJed Brown #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
5078*0a96aa3bSJed Brown PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal diff[])
5079*0a96aa3bSJed Brown {
5080*0a96aa3bSJed Brown   DM             plex;
5081*0a96aa3bSJed Brown   PetscErrorCode ierr;
5082*0a96aa3bSJed Brown 
5083*0a96aa3bSJed Brown   PetscFunctionBegin;
5084*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5085*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5086*0a96aa3bSJed Brown   ierr = DMComputeL2FieldDiff(plex,time,funcs,ctxs,X,diff);CHKERRQ(ierr);
5087*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5088*0a96aa3bSJed Brown }
5089*0a96aa3bSJed Brown 
5090*0a96aa3bSJed Brown #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
5091*0a96aa3bSJed Brown static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
5092*0a96aa3bSJed Brown {
5093*0a96aa3bSJed Brown   DM             plex;
5094*0a96aa3bSJed Brown   PetscSection   section;
5095*0a96aa3bSJed Brown   PetscErrorCode ierr;
5096*0a96aa3bSJed Brown 
5097*0a96aa3bSJed Brown   PetscFunctionBegin;
5098*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5099*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5100*0a96aa3bSJed Brown   ierr = DMGetLocalSection(plex,&section);CHKERRQ(ierr);
5101*0a96aa3bSJed Brown   ierr = DMSetLocalSection(dm,section);CHKERRQ(ierr);
5102*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5103*0a96aa3bSJed Brown }
5104*0a96aa3bSJed Brown 
5105*0a96aa3bSJed Brown #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
5106*0a96aa3bSJed Brown static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
5107*0a96aa3bSJed Brown {
5108*0a96aa3bSJed Brown   DM             plex;
5109*0a96aa3bSJed Brown   Mat            mat;
5110*0a96aa3bSJed Brown   PetscSection   section;
5111*0a96aa3bSJed Brown   PetscErrorCode ierr;
5112*0a96aa3bSJed Brown 
5113*0a96aa3bSJed Brown   PetscFunctionBegin;
5114*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5115*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5116*0a96aa3bSJed Brown   ierr = DMGetDefaultConstraints(plex,&section,&mat);CHKERRQ(ierr);
5117*0a96aa3bSJed Brown   ierr = DMSetDefaultConstraints(dm,section,mat);CHKERRQ(ierr);
5118*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5119*0a96aa3bSJed Brown }
5120*0a96aa3bSJed Brown 
5121*0a96aa3bSJed Brown #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
5122*0a96aa3bSJed Brown static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
5123*0a96aa3bSJed Brown {
5124*0a96aa3bSJed Brown   DM             plex;
5125*0a96aa3bSJed Brown   PetscErrorCode ierr;
5126*0a96aa3bSJed Brown 
5127*0a96aa3bSJed Brown   PetscFunctionBegin;
5128*0a96aa3bSJed Brown   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5129*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5130*0a96aa3bSJed Brown   ierr = DMGetDimPoints(plex,dim,cStart,cEnd);CHKERRQ(ierr);
5131*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5132*0a96aa3bSJed Brown }
5133*0a96aa3bSJed Brown 
5134*0a96aa3bSJed Brown /* Need to forward declare */
5135*0a96aa3bSJed Brown #define DMInitialize_pforest _append_pforest(DMInitialize)
5136*0a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm);
5137*0a96aa3bSJed Brown 
5138*0a96aa3bSJed Brown #define DMClone_pforest _append_pforest(DMClone)
5139*0a96aa3bSJed Brown static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
5140*0a96aa3bSJed Brown {
5141*0a96aa3bSJed Brown   PetscErrorCode ierr;
5142*0a96aa3bSJed Brown 
5143*0a96aa3bSJed Brown   PetscFunctionBegin;
5144*0a96aa3bSJed Brown   ierr = DMClone_Forest(dm,newdm);CHKERRQ(ierr);
5145*0a96aa3bSJed Brown   ierr = DMInitialize_pforest(*newdm);CHKERRQ(ierr);
5146*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5147*0a96aa3bSJed Brown }
5148*0a96aa3bSJed Brown 
5149*0a96aa3bSJed Brown #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
5150*0a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
5151*0a96aa3bSJed Brown {
5152*0a96aa3bSJed Brown   DM_Forest         *forest;
5153*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
5154*0a96aa3bSJed Brown   PetscInt          overlap;
5155*0a96aa3bSJed Brown   PetscErrorCode    ierr;
5156*0a96aa3bSJed Brown 
5157*0a96aa3bSJed Brown   PetscFunctionBegin;
5158*0a96aa3bSJed Brown   ierr    = DMSetUp(dm);CHKERRQ(ierr);
5159*0a96aa3bSJed Brown   forest  = (DM_Forest*) dm->data;
5160*0a96aa3bSJed Brown   pforest = (DM_Forest_pforest*) forest->data;
5161*0a96aa3bSJed Brown   *cStart = 0;
5162*0a96aa3bSJed Brown   ierr    = DMForestGetPartitionOverlap(dm,&overlap);CHKERRQ(ierr);
5163*0a96aa3bSJed Brown   if (overlap && pforest->ghost) {
5164*0a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
5165*0a96aa3bSJed Brown   } else {
5166*0a96aa3bSJed Brown     *cEnd = pforest->forest->local_num_quadrants;
5167*0a96aa3bSJed Brown   }
5168*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5169*0a96aa3bSJed Brown }
5170*0a96aa3bSJed Brown 
5171*0a96aa3bSJed Brown #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
5172*0a96aa3bSJed Brown static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
5173*0a96aa3bSJed Brown {
5174*0a96aa3bSJed Brown   DM_Forest         *forest;
5175*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
5176*0a96aa3bSJed Brown   PetscMPIInt       rank;
5177*0a96aa3bSJed Brown   PetscInt          overlap;
5178*0a96aa3bSJed Brown   PetscInt          cStart, cEnd, cLocalStart, cLocalEnd;
5179*0a96aa3bSJed Brown   PetscInt          nRoots, nLeaves, *mine = NULL;
5180*0a96aa3bSJed Brown   PetscSFNode       *remote = NULL;
5181*0a96aa3bSJed Brown   PetscSF           sf;
5182*0a96aa3bSJed Brown   PetscErrorCode    ierr;
5183*0a96aa3bSJed Brown 
5184*0a96aa3bSJed Brown   PetscFunctionBegin;
5185*0a96aa3bSJed Brown   ierr        = DMForestGetCellChart(dm,&cStart,&cEnd);CHKERRQ(ierr);
5186*0a96aa3bSJed Brown   forest      = (DM_Forest*)         dm->data;
5187*0a96aa3bSJed Brown   pforest     = (DM_Forest_pforest*) forest->data;
5188*0a96aa3bSJed Brown   nRoots      = cEnd - cStart;
5189*0a96aa3bSJed Brown   cLocalStart = pforest->cLocalStart;
5190*0a96aa3bSJed Brown   cLocalEnd   = pforest->cLocalEnd;
5191*0a96aa3bSJed Brown   nLeaves     = 0;
5192*0a96aa3bSJed Brown   ierr        = DMForestGetPartitionOverlap(dm,&overlap);CHKERRQ(ierr);
5193*0a96aa3bSJed Brown   ierr        = MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank);CHKERRMPI(ierr);
5194*0a96aa3bSJed Brown   if (overlap && pforest->ghost) {
5195*0a96aa3bSJed Brown     PetscSFNode      *mirror;
5196*0a96aa3bSJed Brown     p4est_quadrant_t *mirror_array;
5197*0a96aa3bSJed Brown     PetscInt         nMirror, nGhostPre, nSelf, q;
5198*0a96aa3bSJed Brown     void             **mirrorPtrs;
5199*0a96aa3bSJed Brown 
5200*0a96aa3bSJed Brown     nMirror      = (PetscInt) pforest->ghost->mirrors.elem_count;
5201*0a96aa3bSJed Brown     nSelf        = cLocalEnd - cLocalStart;
5202*0a96aa3bSJed Brown     nLeaves      = nRoots - nSelf;
5203*0a96aa3bSJed Brown     nGhostPre    = (PetscInt) pforest->ghost->proc_offsets[rank];
5204*0a96aa3bSJed Brown     ierr         = PetscMalloc1(nLeaves,&mine);CHKERRQ(ierr);
5205*0a96aa3bSJed Brown     ierr         = PetscMalloc1(nLeaves,&remote);CHKERRQ(ierr);
5206*0a96aa3bSJed Brown     ierr         = PetscMalloc2(nMirror,&mirror,nMirror,&mirrorPtrs);CHKERRQ(ierr);
5207*0a96aa3bSJed Brown     mirror_array = (p4est_quadrant_t*) pforest->ghost->mirrors.array;
5208*0a96aa3bSJed Brown     for (q = 0; q < nMirror; q++) {
5209*0a96aa3bSJed Brown       p4est_quadrant_t *mir = &(mirror_array[q]);
5210*0a96aa3bSJed Brown 
5211*0a96aa3bSJed Brown       mirror[q].rank  = rank;
5212*0a96aa3bSJed Brown       mirror[q].index = (PetscInt) mir->p.piggy3.local_num + cLocalStart;
5213*0a96aa3bSJed Brown       mirrorPtrs[q]   = (void*) &(mirror[q]);
5214*0a96aa3bSJed Brown     }
5215*0a96aa3bSJed Brown     PetscStackCallP4est(p4est_ghost_exchange_custom,(pforest->forest,pforest->ghost,sizeof(PetscSFNode),mirrorPtrs,remote));
5216*0a96aa3bSJed Brown     ierr = PetscFree2(mirror,mirrorPtrs);CHKERRQ(ierr);
5217*0a96aa3bSJed Brown     for (q = 0; q < nGhostPre; q++) mine[q] = q;
5218*0a96aa3bSJed Brown     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
5219*0a96aa3bSJed Brown   }
5220*0a96aa3bSJed Brown   ierr    = PetscSFCreate(PetscObjectComm((PetscObject)dm),&sf);CHKERRQ(ierr);
5221*0a96aa3bSJed Brown   ierr    = PetscSFSetGraph(sf,nRoots,nLeaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER);CHKERRQ(ierr);
5222*0a96aa3bSJed Brown   *cellSF = sf;
5223*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5224*0a96aa3bSJed Brown }
5225*0a96aa3bSJed Brown 
5226*0a96aa3bSJed Brown static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS* ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void*), void **setup_ctx)
5227*0a96aa3bSJed Brown {
5228*0a96aa3bSJed Brown   DM             plex;
5229*0a96aa3bSJed Brown   PetscErrorCode ierr;
5230*0a96aa3bSJed Brown 
5231*0a96aa3bSJed Brown   PetscFunctionBegin;
5232*0a96aa3bSJed Brown   ierr = DMPforestGetPlex(dm,&plex);CHKERRQ(ierr);
5233*0a96aa3bSJed Brown   ierr = DMCreateNeumannOverlap_Plex(plex,ovl,J,setup,setup_ctx);CHKERRQ(ierr);
5234*0a96aa3bSJed Brown   if (!*setup) {
5235*0a96aa3bSJed Brown     ierr = PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup);CHKERRQ(ierr);
5236*0a96aa3bSJed Brown     if (*setup) {
5237*0a96aa3bSJed Brown       ierr = PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm);CHKERRQ(ierr);
5238*0a96aa3bSJed Brown     }
5239*0a96aa3bSJed Brown   }
5240*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5241*0a96aa3bSJed Brown }
5242*0a96aa3bSJed Brown 
5243*0a96aa3bSJed Brown static PetscErrorCode DMInitialize_pforest(DM dm)
5244*0a96aa3bSJed Brown {
5245*0a96aa3bSJed Brown   PetscErrorCode ierr;
5246*0a96aa3bSJed Brown 
5247*0a96aa3bSJed Brown   PetscFunctionBegin;
5248*0a96aa3bSJed Brown   dm->ops->setup                     = DMSetUp_pforest;
5249*0a96aa3bSJed Brown   dm->ops->view                      = DMView_pforest;
5250*0a96aa3bSJed Brown   dm->ops->clone                     = DMClone_pforest;
5251*0a96aa3bSJed Brown   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
5252*0a96aa3bSJed Brown   dm->ops->createinjection           = DMCreateInjection_pforest;
5253*0a96aa3bSJed Brown   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
5254*0a96aa3bSJed Brown   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
5255*0a96aa3bSJed Brown   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
5256*0a96aa3bSJed Brown   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
5257*0a96aa3bSJed Brown   dm->ops->creatematrix              = DMCreateMatrix_pforest;
5258*0a96aa3bSJed Brown   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
5259*0a96aa3bSJed Brown   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
5260*0a96aa3bSJed Brown   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
5261*0a96aa3bSJed Brown   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
5262*0a96aa3bSJed Brown   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
5263*0a96aa3bSJed Brown   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
5264*0a96aa3bSJed Brown   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
5265*0a96aa3bSJed Brown   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
5266*0a96aa3bSJed Brown 
5267*0a96aa3bSJed Brown   ierr = PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",DMConvert_plex_pforest);CHKERRQ(ierr);
5268*0a96aa3bSJed Brown   ierr = PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",DMConvert_pforest_plex);CHKERRQ(ierr);
5269*0a96aa3bSJed Brown   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_pforest);CHKERRQ(ierr);
5270*0a96aa3bSJed Brown   ierr = PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMForestGetPartitionOverlap);CHKERRQ(ierr);
5271*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5272*0a96aa3bSJed Brown }
5273*0a96aa3bSJed Brown 
5274*0a96aa3bSJed Brown #define DMCreate_pforest _append_pforest(DMCreate)
5275*0a96aa3bSJed Brown PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
5276*0a96aa3bSJed Brown {
5277*0a96aa3bSJed Brown   DM_Forest         *forest;
5278*0a96aa3bSJed Brown   DM_Forest_pforest *pforest;
5279*0a96aa3bSJed Brown   PetscErrorCode    ierr;
5280*0a96aa3bSJed Brown 
5281*0a96aa3bSJed Brown   PetscFunctionBegin;
5282*0a96aa3bSJed Brown   ierr = PetscP4estInitialize();CHKERRQ(ierr);
5283*0a96aa3bSJed Brown   ierr = DMCreate_Forest(dm);CHKERRQ(ierr);
5284*0a96aa3bSJed Brown   ierr = DMInitialize_pforest(dm);CHKERRQ(ierr);
5285*0a96aa3bSJed Brown   ierr = DMSetDimension(dm,P4EST_DIM);CHKERRQ(ierr);
5286*0a96aa3bSJed Brown 
5287*0a96aa3bSJed Brown   /* set forest defaults */
5288*0a96aa3bSJed Brown   ierr = DMForestSetTopology(dm,"unit");CHKERRQ(ierr);
5289*0a96aa3bSJed Brown   ierr = DMForestSetMinimumRefinement(dm,0);CHKERRQ(ierr);
5290*0a96aa3bSJed Brown   ierr = DMForestSetInitialRefinement(dm,0);CHKERRQ(ierr);
5291*0a96aa3bSJed Brown   ierr = DMForestSetMaximumRefinement(dm,P4EST_QMAXLEVEL);CHKERRQ(ierr);
5292*0a96aa3bSJed Brown   ierr = DMForestSetGradeFactor(dm,2);CHKERRQ(ierr);
5293*0a96aa3bSJed Brown   ierr = DMForestSetAdjacencyDimension(dm,0);CHKERRQ(ierr);
5294*0a96aa3bSJed Brown   ierr = DMForestSetPartitionOverlap(dm,0);CHKERRQ(ierr);
5295*0a96aa3bSJed Brown 
5296*0a96aa3bSJed Brown   /* create p4est data */
5297*0a96aa3bSJed Brown   ierr = PetscNewLog(dm,&pforest);CHKERRQ(ierr);
5298*0a96aa3bSJed Brown 
5299*0a96aa3bSJed Brown   forest                            = (DM_Forest*) dm->data;
5300*0a96aa3bSJed Brown   forest->data                      = pforest;
5301*0a96aa3bSJed Brown   forest->destroy                   = DMForestDestroy_pforest;
5302*0a96aa3bSJed Brown   forest->ftemplate                 = DMForestTemplate_pforest;
5303*0a96aa3bSJed Brown   forest->transfervec               = DMForestTransferVec_pforest;
5304*0a96aa3bSJed Brown   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
5305*0a96aa3bSJed Brown   forest->createcellchart           = DMForestCreateCellChart_pforest;
5306*0a96aa3bSJed Brown   forest->createcellsf              = DMForestCreateCellSF_pforest;
5307*0a96aa3bSJed Brown   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
5308*0a96aa3bSJed Brown   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
5309*0a96aa3bSJed Brown   pforest->topo                     = NULL;
5310*0a96aa3bSJed Brown   pforest->forest                   = NULL;
5311*0a96aa3bSJed Brown   pforest->ghost                    = NULL;
5312*0a96aa3bSJed Brown   pforest->lnodes                   = NULL;
5313*0a96aa3bSJed Brown   pforest->partition_for_coarsening = PETSC_TRUE;
5314*0a96aa3bSJed Brown   pforest->coarsen_hierarchy        = PETSC_FALSE;
5315*0a96aa3bSJed Brown   pforest->cLocalStart              = -1;
5316*0a96aa3bSJed Brown   pforest->cLocalEnd                = -1;
5317*0a96aa3bSJed Brown   pforest->labelsFinalized          = PETSC_FALSE;
5318*0a96aa3bSJed Brown   pforest->ghostName                = NULL;
5319*0a96aa3bSJed Brown   PetscFunctionReturn(0);
5320*0a96aa3bSJed Brown }
5321*0a96aa3bSJed Brown 
5322*0a96aa3bSJed Brown #endif /* defined(PETSC_HAVE_P4EST) */
5323