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