xref: /petsc/src/dm/impls/forest/p4est/pforest.h (revision 852b71a73babaca4c30d2f62c4ac9c0525145e5b)
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 PforestQuadrantIsInterior (p4est_quadrant_t *quad, PetscBool *is_interior)
3901 {
3902   PetscFunctionBegin;
3903   p4est_qcoord_t h = P4EST_QUADRANT_LEN (quad->level);
3904   if ((quad->x > 0) && (quad->x + h < P4EST_ROOT_LEN)
3905 #ifdef P4_TO_P8
3906       && (quad->z > 0) && (quad->z + h < P4EST_ROOT_LEN)
3907 #endif
3908       && (quad->y > 0) && (quad->y + h < P4EST_ROOT_LEN)) {
3909     *is_interior = PETSC_TRUE;
3910   } else {
3911     *is_interior = PETSC_FALSE;
3912   }
3913   PetscFunctionReturn(0);
3914 }
3915 
3916 /* We always use DG coordinates with p4est: if they do not match the vertex
3917    coordinates, add space for them in the section */
3918 static PetscErrorCode PforestCheckLocalizeCell(DM plex, PetscInt cDim, Vec cVecOld, DM_Forest_pforest *pforest, PetscSection oldSection, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad)
3919 {
3920   PetscBool is_interior;
3921 
3922   PetscFunctionBegin;
3923   PetscCall(PforestQuadrantIsInterior(quad, &is_interior));
3924   if (is_interior) { // quads in the interior of a coarse cell can't touch periodic interfaces
3925     PetscCall(PetscSectionSetDof(newSection, cell, 0));
3926     PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3927   } else {
3928     PetscInt     cSize;
3929     PetscScalar *values = NULL;
3930     PetscBool    same_coords = PETSC_TRUE;
3931 
3932     PetscCall(DMPlexVecGetClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3933     PetscAssert(cSize == cDim * P4EST_CHILDREN, PETSC_COMM_SELF, PETSC_ERR_PLIB, "Unexpected closure size");
3934     for (int c = 0; c < P4EST_CHILDREN; c++) {
3935       p4est_qcoord_t quad_coords[3];
3936       p4est_qcoord_t h = P4EST_QUADRANT_LEN (quad->level);
3937       double         corner_coords[3];
3938       double         vert_coords[3];
3939       PetscInt corner = PetscVertToP4estVert[c];
3940 
3941       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
3942         vert_coords[d] = PetscRealPart(values[c * cDim + d]);
3943       }
3944 
3945       quad_coords[0] = quad->x;
3946       quad_coords[1] = quad->y;
3947 #ifdef P4_TO_P8
3948       quad_coords[2] = quad->z;
3949 #endif
3950       for (int d = 0; d < 3; d++) {
3951         quad_coords[d] += (corner & (1 << d)) ? h : 0;
3952       }
3953 #ifndef P4_TO_P8
3954       PetscStackCallP4est(p4est_qcoord_to_vertex,(pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
3955 #else
3956       PetscStackCallP4est(p4est_qcoord_to_vertex,(pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
3957 #endif
3958       for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
3959         if (fabs (vert_coords[d] - corner_coords[d]) > PETSC_SMALL) {
3960           same_coords = PETSC_FALSE;
3961           break;
3962         }
3963       }
3964     }
3965     if (same_coords) {
3966       PetscCall(PetscSectionSetDof(newSection, cell, 0));
3967       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, 0));
3968     } else {
3969       PetscCall(PetscSectionSetDof(newSection, cell, cSize));
3970       PetscCall(PetscSectionSetFieldDof(newSection, cell, 0, cSize));
3971     }
3972     PetscCall(DMPlexVecRestoreClosure(plex, oldSection, cVecOld, cell, &cSize, &values));
3973   }
3974   PetscFunctionReturn(0);
3975 }
3976 
3977 static PetscErrorCode PforestLocalizeCell(DM plex, PetscInt cDim, DM_Forest_pforest *pforest, PetscSection newSection, PetscInt cell, PetscInt coarsePoint, p4est_quadrant_t *quad, PetscScalar coords[])
3978 {
3979   PetscInt  cdof, off;
3980 
3981   PetscFunctionBegin;
3982   PetscCall(PetscSectionGetDof(newSection, cell, &cdof));
3983   if (!cdof) PetscFunctionReturn(0);
3984 
3985   PetscCall(PetscSectionGetOffset(newSection, cell, &off));
3986   for (PetscInt c = 0, pos = off; c < P4EST_CHILDREN; c++) {
3987     p4est_qcoord_t quad_coords[3];
3988     p4est_qcoord_t h = P4EST_QUADRANT_LEN (quad->level);
3989     double         corner_coords[3];
3990     PetscInt corner = PetscVertToP4estVert[c];
3991 
3992     quad_coords[0] = quad->x;
3993     quad_coords[1] = quad->y;
3994 #ifdef P4_TO_P8
3995     quad_coords[2] = quad->z;
3996 #endif
3997     for (int d = 0; d < 3; d++) {
3998       quad_coords[d] += (corner & (1 << d)) ? h : 0;
3999     }
4000 #ifndef P4_TO_P8
4001     PetscStackCallP4est(p4est_qcoord_to_vertex,(pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], corner_coords));
4002 #else
4003     PetscStackCallP4est(p4est_qcoord_to_vertex,(pforest->forest->connectivity, coarsePoint, quad_coords[0], quad_coords[1], quad_coords[2], corner_coords));
4004 #endif
4005     for (PetscInt d = 0; d < PetscMin(cDim, 3); d++) {
4006       coords[pos++] = corner_coords[d];
4007     }
4008     for (PetscInt d = PetscMin(cDim, 3); d < cDim; d++) {
4009       coords[pos++] = 0.;
4010     }
4011   }
4012   PetscFunctionReturn(0);
4013 }
4014 
4015 static PetscErrorCode DMPforestLocalizeCoordinates(DM dm, DM plex)
4016 {
4017   DM_Forest         *forest;
4018   DM_Forest_pforest *pforest;
4019   DM                base, cdm, cdmCell;
4020   Vec               cVec, cVecOld;
4021   PetscSection      oldSection, newSection;
4022   PetscScalar       *coords2;
4023   const PetscReal   *L;
4024   PetscInt          cLocalStart, cLocalEnd, coarsePoint;
4025   PetscInt          cDim, newStart, newEnd;
4026   PetscInt          v, vStart, vEnd, cp, cStart, cEnd, cEndInterior;
4027   p4est_topidx_t    flt, llt, t;
4028   p4est_tree_t      *trees;
4029   PetscBool         baseLocalized = PETSC_FALSE;
4030 
4031   PetscFunctionBegin;
4032   PetscCall(DMGetPeriodicity(dm,NULL,&L));
4033   /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */
4034   PetscCall(DMGetCoordinateDim(dm, &cDim));
4035   PetscCall(DMForestGetBaseDM(dm,&base));
4036   if (base) PetscCall(DMGetCoordinatesLocalized(base,&baseLocalized));
4037   if (!baseLocalized) base = NULL;
4038   if (!baseLocalized && !L) PetscFunctionReturn(0);
4039   PetscCall(DMPlexGetChart(plex, &newStart, &newEnd));
4040 
4041   PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &newSection));
4042   PetscCall(PetscSectionSetNumFields(newSection, 1));
4043   PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim));
4044   PetscCall(PetscSectionSetChart(newSection, newStart, newEnd));
4045 
4046   PetscCall(DMGetCoordinateSection(plex, &oldSection));
4047   PetscCall(DMPlexGetDepthStratum(plex, 0, &vStart, &vEnd));
4048   PetscCall(DMGetCoordinatesLocal(plex, &cVecOld));
4049 
4050   forest      = (DM_Forest*) dm->data;
4051   pforest     = (DM_Forest_pforest*) forest->data;
4052   cLocalStart = pforest->cLocalStart;
4053   cLocalEnd   = pforest->cLocalEnd;
4054   flt         = pforest->forest->first_local_tree;
4055   llt         = pforest->forest->last_local_tree;
4056   trees       = (p4est_tree_t*) pforest->forest->trees->array;
4057 
4058   PetscCall(DMPlexGetHeightStratum(plex, 0, &cStart, &cEnd));
4059   PetscCall(DMPlexGetGhostCellStratum(plex, &cEndInterior, NULL));
4060   cEnd = cEndInterior < 0 ? cEnd : cEndInterior;
4061   cp = 0;
4062   if (cLocalStart > 0) {
4063     p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4064     PetscInt         cell;
4065 
4066     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
4067       p4est_quadrant_t *quad = &ghosts[cell];
4068 
4069       coarsePoint = quad->p.which_tree;
4070       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
4071     }
4072   }
4073   for (t = flt; t <= llt; t++) {
4074     p4est_tree_t *tree    = &(trees[t]);
4075     PetscInt     offset   = cLocalStart + tree->quadrants_offset;
4076     PetscInt     numQuads = (PetscInt) tree->quadrants.elem_count;
4077     p4est_quadrant_t *quads = (p4est_quadrant_t *) tree->quadrants.array;
4078     PetscInt     i;
4079 
4080     if (!numQuads) continue;
4081     coarsePoint = t;
4082     for (i = 0; i < numQuads; i++, cp++) {
4083       PetscInt cell = i + offset;
4084       p4est_quadrant_t * quad = &quads[i];
4085 
4086       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
4087     }
4088   }
4089   if (cLocalEnd - cLocalStart < cEnd - cStart) {
4090     p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4091     PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
4092     PetscInt         count;
4093 
4094     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
4095       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
4096       coarsePoint = quad->p.which_tree;
4097       PetscInt cell = count + cLocalEnd;
4098 
4099       PetscCall(PforestCheckLocalizeCell(plex, cDim, cVecOld, pforest, oldSection, newSection, cell, coarsePoint, quad));
4100     }
4101   }
4102   PetscAssert(cp == cEnd - cStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT,cp,cEnd-cStart);
4103 
4104   PetscCall(PetscSectionSetUp(newSection));
4105   PetscCall(DMGetCoordinateDM(plex, &cdm));
4106   PetscCall(DMClone(cdm, &cdmCell));
4107   PetscCall(DMSetCellCoordinateDM(plex, cdmCell));
4108   PetscCall(DMDestroy(&cdmCell));
4109   PetscCall(DMSetCellCoordinateSection(plex, cDim, newSection));
4110   PetscCall(PetscSectionGetStorageSize(newSection, &v));
4111   PetscCall(VecCreate(PETSC_COMM_SELF, &cVec));
4112   PetscCall(PetscObjectSetName((PetscObject) cVec, "coordinates"));
4113   PetscCall(VecSetBlockSize(cVec, cDim));
4114   PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE));
4115   PetscCall(VecSetType(cVec, VECSTANDARD));
4116   PetscCall(VecSet(cVec, PETSC_MIN_REAL));
4117 
4118   /* Localize coordinates on cells if needed */
4119   PetscCall(VecGetArray(cVec, &coords2));
4120   cp = 0;
4121   if (cLocalStart > 0) {
4122     p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4123     PetscInt         cell;
4124 
4125     for (cell = 0; cell < cLocalStart; ++cell, cp++) {
4126       p4est_quadrant_t *quad = &ghosts[cell];
4127 
4128       coarsePoint = quad->p.which_tree;
4129       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4130     }
4131   }
4132   for (t = flt; t <= llt; t++) {
4133     p4est_tree_t *tree    = &(trees[t]);
4134     PetscInt     offset   = cLocalStart + tree->quadrants_offset;
4135     PetscInt     numQuads = (PetscInt) tree->quadrants.elem_count;
4136     p4est_quadrant_t *quads = (p4est_quadrant_t *) tree->quadrants.array;
4137     PetscInt     i;
4138 
4139     if (!numQuads) continue;
4140     coarsePoint = t;
4141     for (i = 0; i < numQuads; i++, cp++) {
4142       PetscInt cell = i + offset;
4143       p4est_quadrant_t * quad = &quads[i];
4144 
4145       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4146     }
4147   }
4148   if (cLocalEnd - cLocalStart < cEnd - cStart) {
4149     p4est_quadrant_t *ghosts   = (p4est_quadrant_t*) pforest->ghost->ghosts.array;
4150     PetscInt         numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count;
4151     PetscInt         count;
4152 
4153     for (count = 0; count < numGhosts - cLocalStart; count++, cp++) {
4154       p4est_quadrant_t *quad = &ghosts[count + cLocalStart];
4155       coarsePoint = quad->p.which_tree;
4156       PetscInt cell = count + cLocalEnd;
4157 
4158       PetscCall(PforestLocalizeCell(plex, cDim, pforest, newSection, cell, coarsePoint, quad, coords2));
4159     }
4160   }
4161   PetscCall(VecRestoreArray(cVec, &coords2));
4162   PetscCall(DMSetCellCoordinatesLocal(plex, cVec));
4163   PetscCall(VecDestroy(&cVec));
4164   PetscCall(PetscSectionDestroy(&newSection));
4165   PetscFunctionReturn(0);
4166 }
4167 
4168 #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest)
4169 static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm)
4170 {
4171   DM_Forest         *forest;
4172   DM_Forest_pforest *pforest;
4173 
4174   PetscFunctionBegin;
4175   forest  = (DM_Forest*) dm->data;
4176   pforest = (DM_Forest_pforest *) forest->data;
4177   PetscCall(PetscSFDestroy(&(pforest->pointAdaptToSelfSF)));
4178   PetscCall(PetscSFDestroy(&(pforest->pointSelfToAdaptSF)));
4179   PetscCall(PetscFree(pforest->pointAdaptToSelfCids));
4180   PetscCall(PetscFree(pforest->pointSelfToAdaptCids));
4181   PetscFunctionReturn(0);
4182 }
4183 
4184 static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex)
4185 {
4186   DM_Forest            *forest;
4187   DM_Forest_pforest    *pforest;
4188   DM                   refTree, newPlex, base;
4189   PetscInt             adjDim, adjCodim, coordDim;
4190   MPI_Comm             comm;
4191   PetscBool            isPforest;
4192   PetscInt             dim;
4193   PetscInt             overlap;
4194   p4est_connect_type_t ctype;
4195   p4est_locidx_t       first_local_quad = -1;
4196   sc_array_t           *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes;
4197   PetscSection         parentSection;
4198   PetscSF              pointSF;
4199   size_t               zz, count;
4200   PetscInt             pStart, pEnd;
4201   DMLabel              ghostLabelBase = NULL;
4202 
4203   PetscFunctionBegin;
4204 
4205   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4206   comm = PetscObjectComm((PetscObject)dm);
4207   PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPFOREST,&isPforest));
4208   PetscCheck(isPforest,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPFOREST,((PetscObject)dm)->type_name);
4209   PetscCall(DMGetDimension(dm,&dim));
4210   PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim);
4211   forest  = (DM_Forest*) dm->data;
4212   pforest = (DM_Forest_pforest*) forest->data;
4213   PetscCall(DMForestGetBaseDM(dm,&base));
4214   if (base) {
4215     PetscCall(DMGetLabel(base,"ghost",&ghostLabelBase));
4216   }
4217   if (!pforest->plex) {
4218     PetscMPIInt size;
4219 
4220     PetscCallMPI(MPI_Comm_size(comm,&size));
4221     PetscCall(DMCreate(comm,&newPlex));
4222     PetscCall(DMSetType(newPlex,DMPLEX));
4223     PetscCall(DMSetMatType(newPlex,dm->mattype));
4224     /* share labels */
4225     PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
4226     PetscCall(DMForestGetAdjacencyDimension(dm,&adjDim));
4227     PetscCall(DMForestGetAdjacencyCodimension(dm,&adjCodim));
4228     PetscCall(DMGetCoordinateDim(dm,&coordDim));
4229     if (adjDim == 0) {
4230       ctype = P4EST_CONNECT_FULL;
4231     } else if (adjCodim == 1) {
4232       ctype = P4EST_CONNECT_FACE;
4233 #if defined(P4_TO_P8)
4234     } else if (adjDim == 1) {
4235       ctype = P8EST_CONNECT_EDGE;
4236 #endif
4237     } else {
4238       SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Invalid adjacency dimension %" PetscInt_FMT,adjDim);
4239     }
4240     PetscCheck(ctype == P4EST_CONNECT_FULL,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Adjacency dimension %" PetscInt_FMT " / codimension %" PetscInt_FMT " not supported yet",adjDim,adjCodim);
4241     PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
4242     PetscCall(DMPlexSetOverlap_Plex(newPlex,NULL,overlap));
4243 
4244     points_per_dim    = sc_array_new(sizeof(p4est_locidx_t));
4245     cone_sizes        = sc_array_new(sizeof(p4est_locidx_t));
4246     cones             = sc_array_new(sizeof(p4est_locidx_t));
4247     cone_orientations = sc_array_new(sizeof(p4est_locidx_t));
4248     coords            = sc_array_new(3 * sizeof(double));
4249     children          = sc_array_new(sizeof(p4est_locidx_t));
4250     parents           = sc_array_new(sizeof(p4est_locidx_t));
4251     childids          = sc_array_new(sizeof(p4est_locidx_t));
4252     leaves            = sc_array_new(sizeof(p4est_locidx_t));
4253     remotes           = sc_array_new(2 * sizeof(p4est_locidx_t));
4254 
4255     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));
4256 
4257     pforest->cLocalStart = (PetscInt) first_local_quad;
4258     pforest->cLocalEnd   = pforest->cLocalStart + (PetscInt) pforest->forest->local_num_quadrants;
4259     PetscCall(locidx_to_PetscInt(points_per_dim));
4260     PetscCall(locidx_to_PetscInt(cone_sizes));
4261     PetscCall(locidx_to_PetscInt(cones));
4262     PetscCall(locidx_to_PetscInt(cone_orientations));
4263     PetscCall(coords_double_to_PetscScalar(coords, coordDim));
4264     PetscCall(locidx_to_PetscInt(children));
4265     PetscCall(locidx_to_PetscInt(parents));
4266     PetscCall(locidx_to_PetscInt(childids));
4267     PetscCall(locidx_to_PetscInt(leaves));
4268     PetscCall(locidx_pair_to_PetscSFNode(remotes));
4269 
4270     PetscCall(DMSetDimension(newPlex,P4EST_DIM));
4271     PetscCall(DMSetCoordinateDim(newPlex,coordDim));
4272     PetscCall(DMPlexSetMaxProjectionHeight(newPlex,P4EST_DIM - 1));
4273     PetscCall(DMPlexCreateFromDAG(newPlex,P4EST_DIM,(PetscInt*)points_per_dim->array,(PetscInt*)cone_sizes->array,(PetscInt*)cones->array,(PetscInt*)cone_orientations->array,(PetscScalar*)coords->array));
4274     PetscCall(DMPlexConvertOldOrientations_Internal(newPlex));
4275     PetscCall(DMCreateReferenceTree_pforest(comm,&refTree));
4276     PetscCall(DMPlexSetReferenceTree(newPlex,refTree));
4277     PetscCall(PetscSectionCreate(comm,&parentSection));
4278     PetscCall(DMPlexGetChart(newPlex,&pStart,&pEnd));
4279     PetscCall(PetscSectionSetChart(parentSection,pStart,pEnd));
4280     count = children->elem_count;
4281     for (zz = 0; zz < count; zz++) {
4282       PetscInt child = *((PetscInt*) sc_array_index(children,zz));
4283 
4284       PetscCall(PetscSectionSetDof(parentSection,child,1));
4285     }
4286     PetscCall(PetscSectionSetUp(parentSection));
4287     PetscCall(DMPlexSetTree(newPlex,parentSection,(PetscInt*)parents->array,(PetscInt*)childids->array));
4288     PetscCall(PetscSectionDestroy(&parentSection));
4289     PetscCall(PetscSFCreate(comm,&pointSF));
4290     /*
4291        These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order.
4292        https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391
4293     */
4294     PetscCall(PetscSFSetGraph(pointSF,pEnd - pStart,(PetscInt)leaves->elem_count,(PetscInt*)leaves->array,PETSC_COPY_VALUES,(PetscSFNode*)remotes->array,PETSC_COPY_VALUES));
4295     PetscCall(DMSetPointSF(newPlex,pointSF));
4296     PetscCall(DMSetPointSF(dm,pointSF));
4297     {
4298       DM coordDM;
4299 
4300       PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
4301       PetscCall(DMSetPointSF(coordDM,pointSF));
4302     }
4303     PetscCall(PetscSFDestroy(&pointSF));
4304     sc_array_destroy (points_per_dim);
4305     sc_array_destroy (cone_sizes);
4306     sc_array_destroy (cones);
4307     sc_array_destroy (cone_orientations);
4308     sc_array_destroy (coords);
4309     sc_array_destroy (children);
4310     sc_array_destroy (parents);
4311     sc_array_destroy (childids);
4312     sc_array_destroy (leaves);
4313     sc_array_destroy (remotes);
4314 
4315     {
4316       const PetscReal *maxCell, *L;
4317 
4318       PetscCall(DMGetPeriodicity(dm,&maxCell,&L));
4319       PetscCall(DMSetPeriodicity(newPlex,maxCell,L));
4320       PetscCall(DMPforestLocalizeCoordinates(dm,newPlex));
4321     }
4322 
4323     if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */
4324       Vec               coordsGlobal, coordsLocal;
4325       const PetscScalar *globalArray;
4326       PetscScalar       *localArray;
4327       PetscSF           coordSF;
4328       DM                coordDM;
4329 
4330       PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
4331       PetscCall(DMGetSectionSF(coordDM,&coordSF));
4332       PetscCall(DMGetCoordinates(newPlex, &coordsGlobal));
4333       PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal));
4334       PetscCall(VecGetArrayRead(coordsGlobal, &globalArray));
4335       PetscCall(VecGetArray(coordsLocal, &localArray));
4336       PetscCall(PetscSFBcastBegin(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
4337       PetscCall(PetscSFBcastEnd(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE));
4338       PetscCall(VecRestoreArray(coordsLocal, &localArray));
4339       PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray));
4340       PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal));
4341     }
4342     PetscCall(DMPforestMapCoordinates(dm,newPlex));
4343 
4344     pforest->plex = newPlex;
4345 
4346     /* copy labels */
4347     PetscCall(DMPforestLabelsFinalize(dm,newPlex));
4348 
4349     if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */
4350       PetscInt numAdded;
4351       DM       newPlexGhosted;
4352       void     *ctx;
4353 
4354       PetscCall(DMPlexConstructGhostCells(newPlex,pforest->ghostName,&numAdded,&newPlexGhosted));
4355       PetscCall(DMGetApplicationContext(newPlex,&ctx));
4356       PetscCall(DMSetApplicationContext(newPlexGhosted,ctx));
4357       /* we want the sf for the ghost dm to be the one for the p4est dm as well */
4358       PetscCall(DMGetPointSF(newPlexGhosted,&pointSF));
4359       PetscCall(DMSetPointSF(dm,pointSF));
4360       PetscCall(DMDestroy(&newPlex));
4361       PetscCall(DMPlexSetReferenceTree(newPlexGhosted,refTree));
4362       PetscCall(DMForestClearAdaptivityForest_pforest(dm));
4363       newPlex = newPlexGhosted;
4364 
4365       /* share the labels back */
4366       PetscCall(DMDestroyLabelLinkList_Internal(dm));
4367       PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL));
4368       pforest->plex = newPlex;
4369     }
4370     PetscCall(DMDestroy(&refTree));
4371     if (dm->setfromoptionscalled) {
4372 
4373       PetscObjectOptionsBegin((PetscObject)newPlex);
4374       PetscCall(DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject,newPlex));
4375       PetscCall(PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)newPlex));
4376       PetscOptionsEnd();
4377     }
4378     PetscCall(DMViewFromOptions(newPlex,NULL,"-dm_p4est_plex_view"));
4379     {
4380       DM           cdm;
4381       PetscSection coordsSec;
4382       Vec          coords;
4383       PetscInt     cDim;
4384 
4385       PetscCall(DMGetCoordinateDim(newPlex, &cDim));
4386       PetscCall(DMGetCoordinateSection(newPlex, &coordsSec));
4387       PetscCall(DMSetCoordinateSection(dm,cDim, coordsSec));
4388       PetscCall(DMGetCoordinatesLocal(newPlex, &coords));
4389       PetscCall(DMSetCoordinatesLocal(dm, coords));
4390       PetscCall(DMGetCellCoordinateDM(newPlex, &cdm));
4391       if (cdm) PetscCall(DMSetCellCoordinateDM(dm, cdm));
4392       PetscCall(DMGetCellCoordinateSection(newPlex, &coordsSec));
4393       if (coordsSec) PetscCall(DMSetCellCoordinateSection(dm, cDim, coordsSec));
4394       PetscCall(DMGetCellCoordinatesLocal(newPlex, &coords));
4395       if (coords) PetscCall(DMSetCellCoordinatesLocal(dm, coords));
4396     }
4397   }
4398   newPlex = pforest->plex;
4399   if (plex) {
4400     PetscCall(DMClone(newPlex,plex));
4401 #if 0
4402     PetscCall(DMGetCoordinateDM(newPlex,&coordDM));
4403     PetscCall(DMSetCoordinateDM(*plex,coordDM));
4404     PetscCall(DMGetCellCoordinateDM(newPlex,&coordDM));
4405     PetscCall(DMSetCellCoordinateDM(*plex,coordDM));
4406 #endif
4407     PetscCall(DMShareDiscretization(dm,*plex));
4408   }
4409   PetscFunctionReturn(0);
4410 }
4411 
4412 static PetscErrorCode DMSetFromOptions_pforest(PetscOptionItems *PetscOptionsObject,DM dm)
4413 {
4414   DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4415   char              stringBuffer[256];
4416   PetscBool         flg;
4417 
4418   PetscFunctionBegin;
4419   PetscCall(DMSetFromOptions_Forest(PetscOptionsObject,dm));
4420   PetscOptionsHeadBegin(PetscOptionsObject,"DM" P4EST_STRING " options");
4421   PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening","partition forest to allow for coarsening","DMP4estSetPartitionForCoarsening",pforest->partition_for_coarsening,&(pforest->partition_for_coarsening),NULL));
4422   PetscCall(PetscOptionsString("-dm_p4est_ghost_label_name","the name of the ghost label when converting from a DMPlex",NULL,NULL,stringBuffer,sizeof(stringBuffer),&flg));
4423   PetscOptionsHeadEnd();
4424   if (flg) {
4425     PetscCall(PetscFree(pforest->ghostName));
4426     PetscCall(PetscStrallocpy(stringBuffer,&pforest->ghostName));
4427   }
4428   PetscFunctionReturn(0);
4429 }
4430 
4431 #if !defined(P4_TO_P8)
4432 #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening
4433 #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening
4434 #else
4435 #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening
4436 #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening
4437 #endif
4438 
4439 PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg)
4440 {
4441   DM_Forest_pforest *pforest;
4442 
4443   PetscFunctionBegin;
4444   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4445   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4446   *flg    = pforest->partition_for_coarsening;
4447   PetscFunctionReturn(0);
4448 }
4449 
4450 PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg)
4451 {
4452   DM_Forest_pforest *pforest;
4453 
4454   PetscFunctionBegin;
4455   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4456   pforest                           = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4457   pforest->partition_for_coarsening = flg;
4458   PetscFunctionReturn(0);
4459 }
4460 
4461 static PetscErrorCode DMPforestGetPlex(DM dm,DM *plex)
4462 {
4463   DM_Forest_pforest *pforest;
4464 
4465   PetscFunctionBegin;
4466   if (plex) *plex = NULL;
4467   PetscCall(DMSetUp(dm));
4468   pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data;
4469   if (!pforest->plex) {
4470     PetscCall(DMConvert_pforest_plex(dm,DMPLEX,NULL));
4471   }
4472   PetscCall(DMShareDiscretization(dm,pforest->plex));
4473   if (plex) *plex = pforest->plex;
4474   PetscFunctionReturn(0);
4475 }
4476 
4477 #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation)
4478 static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling)
4479 {
4480   PetscSection   gsc, gsf;
4481   PetscInt       m, n;
4482   DM             cdm;
4483 
4484   PetscFunctionBegin;
4485   PetscCall(DMGetGlobalSection(dmFine, &gsf));
4486   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m));
4487   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
4488   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n));
4489 
4490   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), interpolation));
4491   PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
4492   PetscCall(MatSetType(*interpolation, MATAIJ));
4493 
4494   PetscCall(DMGetCoarseDM(dmFine, &cdm));
4495   PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only interpolation from coarse DM for now");
4496 
4497   {
4498     DM       plexF, plexC;
4499     PetscSF  sf;
4500     PetscInt *cids;
4501     PetscInt dofPerDim[4] = {1,1,1,1};
4502 
4503     PetscCall(DMPforestGetPlex(dmCoarse,&plexC));
4504     PetscCall(DMPforestGetPlex(dmFine,&plexF));
4505     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
4506     PetscCall(PetscSFSetUp(sf));
4507     PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation));
4508     PetscCall(PetscSFDestroy(&sf));
4509     PetscCall(PetscFree(cids));
4510   }
4511   PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view"));
4512   /* Use naive scaling */
4513   PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling));
4514   PetscFunctionReturn(0);
4515 }
4516 
4517 #define DMCreateInjection_pforest _append_pforest(DMCreateInjection)
4518 static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection)
4519 {
4520   PetscSection   gsc, gsf;
4521   PetscInt       m, n;
4522   DM             cdm;
4523 
4524   PetscFunctionBegin;
4525   PetscCall(DMGetGlobalSection(dmFine, &gsf));
4526   PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n));
4527   PetscCall(DMGetGlobalSection(dmCoarse, &gsc));
4528   PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m));
4529 
4530   PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), injection));
4531   PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE));
4532   PetscCall(MatSetType(*injection, MATAIJ));
4533 
4534   PetscCall(DMGetCoarseDM(dmFine, &cdm));
4535   PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only injection to coarse DM for now");
4536 
4537   {
4538     DM       plexF, plexC;
4539     PetscSF  sf;
4540     PetscInt *cids;
4541     PetscInt dofPerDim[4] = {1,1,1,1};
4542 
4543     PetscCall(DMPforestGetPlex(dmCoarse,&plexC));
4544     PetscCall(DMPforestGetPlex(dmFine,&plexF));
4545     PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids));
4546     PetscCall(PetscSFSetUp(sf));
4547     PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection));
4548     PetscCall(PetscSFDestroy(&sf));
4549     PetscCall(PetscFree(cids));
4550   }
4551   PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view"));
4552   /* Use naive scaling */
4553   PetscFunctionReturn(0);
4554 }
4555 
4556 #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase)
4557 static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut)
4558 {
4559   DM             dmIn, dmVecIn, base, basec, plex, coarseDM;
4560   DM             *hierarchy;
4561   PetscSF        sfRed = NULL;
4562   PetscDS        ds;
4563   Vec            vecInLocal, vecOutLocal;
4564   DMLabel        subpointMap;
4565   PetscInt       minLevel, mh, n_hi, i;
4566   PetscBool      hiforest, *hierarchy_forest;
4567 
4568   PetscFunctionBegin;
4569   PetscCall(VecGetDM(vecIn,&dmVecIn));
4570   PetscCall(DMGetDS(dmVecIn,&ds));
4571   PetscCheck(ds,PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Cannot transfer without a PetscDS object");
4572   { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */
4573     PetscSection section;
4574     PetscInt     Nf;
4575 
4576     PetscCall(DMGetLocalSection(dmVecIn,&section));
4577     PetscCall(PetscSectionGetNumFields(section,&Nf));
4578     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);
4579   }
4580   PetscCall(DMForestGetMinimumRefinement(dm,&minLevel));
4581   PetscCheck(!minLevel,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)",minLevel);
4582   PetscCall(DMForestGetBaseDM(dm,&base));
4583   PetscCheck(base,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing base DM");
4584 
4585   PetscCall(VecSet(vecOut,0.0));
4586   if (dmVecIn == base) { /* sequential runs */
4587     PetscCall(PetscObjectReference((PetscObject)vecIn));
4588   } else {
4589     PetscSection secIn, secInRed;
4590     Vec          vecInRed, vecInLocal;
4591 
4592     PetscCall(PetscObjectQuery((PetscObject)base,"_base_migration_sf",(PetscObject*)&sfRed));
4593     PetscCheck(sfRed,PETSC_COMM_SELF,PETSC_ERR_SUP,"Not the DM set with DMForestSetBaseDM()");
4594     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn),&secInRed));
4595     PetscCall(VecCreate(PETSC_COMM_SELF,&vecInRed));
4596     PetscCall(DMGetLocalSection(dmVecIn,&secIn));
4597     PetscCall(DMGetLocalVector(dmVecIn,&vecInLocal));
4598     PetscCall(DMGlobalToLocalBegin(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
4599     PetscCall(DMGlobalToLocalEnd(dmVecIn,vecIn,INSERT_VALUES,vecInLocal));
4600     PetscCall(DMPlexDistributeField(dmVecIn,sfRed,secIn,vecInLocal,secInRed,vecInRed));
4601     PetscCall(DMRestoreLocalVector(dmVecIn,&vecInLocal));
4602     PetscCall(PetscSectionDestroy(&secInRed));
4603     vecIn = vecInRed;
4604   }
4605 
4606   /* we first search through the AdaptivityForest hierarchy
4607      once we found the first disconnected forest, we upsweep the DM hierarchy */
4608   hiforest = PETSC_TRUE;
4609 
4610   /* upsweep to the coarsest DM */
4611   n_hi = 0;
4612   coarseDM = dm;
4613   do {
4614     PetscBool isforest;
4615 
4616     dmIn = coarseDM;
4617     /* need to call DMSetUp to have the hierarchy recursively setup */
4618     PetscCall(DMSetUp(dmIn));
4619     PetscCall(DMIsForest(dmIn,&isforest));
4620     PetscCheck(isforest,PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Cannot currently transfer through a mixed hierarchy! Found DM type %s",((PetscObject)dmIn)->type_name);
4621     coarseDM = NULL;
4622     if (hiforest) {
4623       PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM));
4624     }
4625     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
4626       hiforest = PETSC_FALSE;
4627       PetscCall(DMGetCoarseDM(dmIn,&coarseDM));
4628     }
4629     n_hi++;
4630   } while (coarseDM);
4631 
4632   PetscCall(PetscMalloc2(n_hi,&hierarchy,n_hi,&hierarchy_forest));
4633 
4634   i = 0;
4635   hiforest = PETSC_TRUE;
4636   coarseDM = dm;
4637   do {
4638     dmIn = coarseDM;
4639     coarseDM = NULL;
4640     if (hiforest) {
4641       PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM));
4642     }
4643     if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */
4644       hiforest = PETSC_FALSE;
4645       PetscCall(DMGetCoarseDM(dmIn,&coarseDM));
4646     }
4647     i++;
4648     hierarchy[n_hi - i] = dmIn;
4649   } while (coarseDM);
4650 
4651   /* project base vector on the coarsest forest (minimum refinement = 0) */
4652   PetscCall(DMPforestGetPlex(dmIn,&plex));
4653 
4654   /* Check this plex is compatible with the base */
4655   {
4656     IS       gnum[2];
4657     PetscInt ncells[2],gncells[2];
4658 
4659     PetscCall(DMPlexGetCellNumbering(base,&gnum[0]));
4660     PetscCall(DMPlexGetCellNumbering(plex,&gnum[1]));
4661     PetscCall(ISGetMinMax(gnum[0],NULL,&ncells[0]));
4662     PetscCall(ISGetMinMax(gnum[1],NULL,&ncells[1]));
4663     PetscCall(MPIU_Allreduce(ncells,gncells,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm)));
4664     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);
4665   }
4666 
4667   PetscCall(DMGetLabel(dmIn,"_forest_base_subpoint_map",&subpointMap));
4668   PetscCheck(subpointMap,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing _forest_base_subpoint_map label");
4669 
4670   PetscCall(DMPlexGetMaxProjectionHeight(base,&mh));
4671   PetscCall(DMPlexSetMaxProjectionHeight(plex,mh));
4672 
4673   PetscCall(DMClone(base,&basec));
4674   PetscCall(DMCopyDisc(dmVecIn,basec));
4675   if (sfRed) {
4676     PetscCall(PetscObjectReference((PetscObject)vecIn));
4677     vecInLocal = vecIn;
4678   } else {
4679     PetscCall(DMCreateLocalVector(basec,&vecInLocal));
4680     PetscCall(DMGlobalToLocalBegin(basec,vecIn,INSERT_VALUES,vecInLocal));
4681     PetscCall(DMGlobalToLocalEnd(basec,vecIn,INSERT_VALUES,vecInLocal));
4682   }
4683 
4684   PetscCall(DMGetLocalVector(dmIn,&vecOutLocal));
4685   { /* get degrees of freedom ordered onto dmIn */
4686     PetscSF            basetocoarse;
4687     PetscInt           bStart, bEnd, nroots;
4688     PetscInt           iStart, iEnd, nleaves, leaf;
4689     PetscMPIInt        rank;
4690     PetscSFNode       *remotes;
4691     PetscSection       secIn, secOut;
4692     PetscInt          *remoteOffsets;
4693     PetscSF            transferSF;
4694     const PetscScalar *inArray;
4695     PetscScalar       *outArray;
4696 
4697     PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank));
4698     PetscCall(DMPlexGetChart(basec, &bStart, &bEnd));
4699     nroots = PetscMax(bEnd - bStart, 0);
4700     PetscCall(DMPlexGetChart(plex, &iStart, &iEnd));
4701     nleaves = PetscMax(iEnd - iStart, 0);
4702 
4703     PetscCall(PetscMalloc1(nleaves, &remotes));
4704     for (leaf = iStart; leaf < iEnd; leaf++) {
4705       PetscInt index;
4706 
4707       remotes[leaf - iStart].rank = rank;
4708       PetscCall(DMLabelGetValue(subpointMap, leaf, &index));
4709       remotes[leaf - iStart].index = index;
4710     }
4711 
4712     PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse));
4713     PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER));
4714     PetscCall(PetscSFSetUp(basetocoarse));
4715     PetscCall(DMGetLocalSection(basec,&secIn));
4716     PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn),&secOut));
4717     PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut));
4718     PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF));
4719     PetscCall(PetscFree(remoteOffsets));
4720     PetscCall(VecGetArrayWrite(vecOutLocal, &outArray));
4721     PetscCall(VecGetArrayRead(vecInLocal, &inArray));
4722     PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
4723     PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE));
4724     PetscCall(VecRestoreArrayRead(vecInLocal, &inArray));
4725     PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray));
4726     PetscCall(PetscSFDestroy(&transferSF));
4727     PetscCall(PetscSectionDestroy(&secOut));
4728     PetscCall(PetscSFDestroy(&basetocoarse));
4729   }
4730   PetscCall(VecDestroy(&vecInLocal));
4731   PetscCall(DMDestroy(&basec));
4732   PetscCall(VecDestroy(&vecIn));
4733 
4734   /* output */
4735   if (n_hi > 1) { /* downsweep the stored hierarchy */
4736     Vec vecOut1, vecOut2;
4737     DM  fineDM;
4738 
4739     PetscCall(DMGetGlobalVector(dmIn,&vecOut1));
4740     PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut1));
4741     PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal));
4742     for (i = 1; i < n_hi-1; i++) {
4743       fineDM  = hierarchy[i];
4744       PetscCall(DMGetGlobalVector(fineDM,&vecOut2));
4745       PetscCall(DMForestTransferVec(dmIn,vecOut1,fineDM,vecOut2,PETSC_TRUE,0.0));
4746       PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1));
4747       vecOut1 = vecOut2;
4748       dmIn    = fineDM;
4749     }
4750     PetscCall(DMForestTransferVec(dmIn,vecOut1,dm,vecOut,PETSC_TRUE,0.0));
4751     PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1));
4752   } else {
4753     PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut));
4754     PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal));
4755   }
4756   PetscCall(PetscFree2(hierarchy,hierarchy_forest));
4757   PetscFunctionReturn(0);
4758 }
4759 
4760 #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec)
4761 static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time)
4762 {
4763   DM             adaptIn, adaptOut, plexIn, plexOut;
4764   DM_Forest      *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut;
4765   PetscInt       dofPerDim[] = {1, 1, 1, 1};
4766   PetscSF        inSF = NULL, outSF = NULL;
4767   PetscInt       *inCids = NULL, *outCids = NULL;
4768   DMAdaptFlag    purposeIn, purposeOut;
4769 
4770   PetscFunctionBegin;
4771   forestOut = (DM_Forest *) dmOut->data;
4772   forestIn  = (DM_Forest *) dmIn->data;
4773 
4774   PetscCall(DMForestGetAdaptivityForest(dmOut,&adaptOut));
4775   PetscCall(DMForestGetAdaptivityPurpose(dmOut,&purposeOut));
4776   forestAdaptOut = adaptOut ? (DM_Forest *) adaptOut->data : NULL;
4777 
4778   PetscCall(DMForestGetAdaptivityForest(dmIn,&adaptIn));
4779   PetscCall(DMForestGetAdaptivityPurpose(dmIn,&purposeIn));
4780   forestAdaptIn  = adaptIn ? (DM_Forest *) adaptIn->data : NULL;
4781 
4782   if (forestAdaptOut == forestIn) {
4783     switch (purposeOut) {
4784     case DM_ADAPT_REFINE:
4785       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
4786       PetscCall(PetscSFSetUp(inSF));
4787       break;
4788     case DM_ADAPT_COARSEN:
4789     case DM_ADAPT_COARSEN_LAST:
4790       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&outCids));
4791       PetscCall(PetscSFSetUp(outSF));
4792       break;
4793     default:
4794       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
4795       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
4796       PetscCall(PetscSFSetUp(inSF));
4797       PetscCall(PetscSFSetUp(outSF));
4798     }
4799   } else if (forestAdaptIn == forestOut) {
4800     switch (purposeIn) {
4801     case DM_ADAPT_REFINE:
4802       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&inCids));
4803       PetscCall(PetscSFSetUp(outSF));
4804       break;
4805     case DM_ADAPT_COARSEN:
4806     case DM_ADAPT_COARSEN_LAST:
4807       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
4808       PetscCall(PetscSFSetUp(inSF));
4809       break;
4810     default:
4811       PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids));
4812       PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids));
4813       PetscCall(PetscSFSetUp(inSF));
4814       PetscCall(PetscSFSetUp(outSF));
4815     }
4816   } else SETERRQ(PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Only support transfer from pre-adaptivity to post-adaptivity right now");
4817   PetscCall(DMPforestGetPlex(dmIn,&plexIn));
4818   PetscCall(DMPforestGetPlex(dmOut,&plexOut));
4819 
4820   PetscCall(DMPlexTransferVecTree(plexIn,vecIn,plexOut,vecOut,inSF,outSF,inCids,outCids,useBCs,time));
4821   PetscCall(PetscFree(inCids));
4822   PetscCall(PetscFree(outCids));
4823   PetscCall(PetscSFDestroy(&inSF));
4824   PetscCall(PetscSFDestroy(&outSF));
4825   PetscCall(PetscFree(inCids));
4826   PetscCall(PetscFree(outCids));
4827   PetscFunctionReturn(0);
4828 }
4829 
4830 #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM)
4831 static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm,DM *cdm)
4832 {
4833   DM             plex;
4834 
4835   PetscFunctionBegin;
4836   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4837   PetscCall(DMPforestGetPlex(dm,&plex));
4838   PetscCall(DMGetCoordinateDM(plex,cdm));
4839   PetscCall(PetscObjectReference((PetscObject)*cdm));
4840   PetscFunctionReturn(0);
4841 }
4842 
4843 #define VecViewLocal_pforest _append_pforest(VecViewLocal)
4844 static PetscErrorCode VecViewLocal_pforest(Vec vec,PetscViewer viewer)
4845 {
4846   DM             dm, plex;
4847 
4848   PetscFunctionBegin;
4849   PetscCall(VecGetDM(vec,&dm));
4850   PetscCall(DMPforestGetPlex(dm,&plex));
4851   PetscCall(VecSetDM(vec,plex));
4852   PetscCall(VecView_Plex_Local(vec,viewer));
4853   PetscCall(VecSetDM(vec,dm));
4854   PetscFunctionReturn(0);
4855 }
4856 
4857 #define VecView_pforest _append_pforest(VecView)
4858 static PetscErrorCode VecView_pforest(Vec vec,PetscViewer viewer)
4859 {
4860   DM             dm, plex;
4861 
4862   PetscFunctionBegin;
4863   PetscCall(VecGetDM(vec,&dm));
4864   PetscCall(DMPforestGetPlex(dm,&plex));
4865   PetscCall(VecSetDM(vec,plex));
4866   PetscCall(VecView_Plex(vec,viewer));
4867   PetscCall(VecSetDM(vec,dm));
4868   PetscFunctionReturn(0);
4869 }
4870 
4871 #define VecView_pforest_Native _infix_pforest(VecView,_Native)
4872 static PetscErrorCode VecView_pforest_Native(Vec vec,PetscViewer viewer)
4873 {
4874   DM             dm, plex;
4875 
4876   PetscFunctionBegin;
4877   PetscCall(VecGetDM(vec,&dm));
4878   PetscCall(DMPforestGetPlex(dm,&plex));
4879   PetscCall(VecSetDM(vec,plex));
4880   PetscCall(VecView_Plex_Native(vec,viewer));
4881   PetscCall(VecSetDM(vec,dm));
4882   PetscFunctionReturn(0);
4883 }
4884 
4885 #define VecLoad_pforest _append_pforest(VecLoad)
4886 static PetscErrorCode VecLoad_pforest(Vec vec,PetscViewer viewer)
4887 {
4888   DM             dm, plex;
4889 
4890   PetscFunctionBegin;
4891   PetscCall(VecGetDM(vec,&dm));
4892   PetscCall(DMPforestGetPlex(dm,&plex));
4893   PetscCall(VecSetDM(vec,plex));
4894   PetscCall(VecLoad_Plex(vec,viewer));
4895   PetscCall(VecSetDM(vec,dm));
4896   PetscFunctionReturn(0);
4897 }
4898 
4899 #define VecLoad_pforest_Native _infix_pforest(VecLoad,_Native)
4900 static PetscErrorCode VecLoad_pforest_Native(Vec vec,PetscViewer viewer)
4901 {
4902   DM             dm, plex;
4903 
4904   PetscFunctionBegin;
4905   PetscCall(VecGetDM(vec,&dm));
4906   PetscCall(DMPforestGetPlex(dm,&plex));
4907   PetscCall(VecSetDM(vec,plex));
4908   PetscCall(VecLoad_Plex_Native(vec,viewer));
4909   PetscCall(VecSetDM(vec,dm));
4910   PetscFunctionReturn(0);
4911 }
4912 
4913 #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector)
4914 static PetscErrorCode DMCreateGlobalVector_pforest(DM dm,Vec *vec)
4915 {
4916   PetscFunctionBegin;
4917   PetscCall(DMCreateGlobalVector_Section_Private(dm,vec));
4918   /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */
4919   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest));
4920   PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native));
4921   PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest));
4922   PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native));
4923   PetscFunctionReturn(0);
4924 }
4925 
4926 #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector)
4927 static PetscErrorCode DMCreateLocalVector_pforest(DM dm,Vec *vec)
4928 {
4929   PetscFunctionBegin;
4930   PetscCall(DMCreateLocalVector_Section_Private(dm,vec));
4931   PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest));
4932   PetscFunctionReturn(0);
4933 }
4934 
4935 #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix)
4936 static PetscErrorCode DMCreateMatrix_pforest(DM dm,Mat *mat)
4937 {
4938   DM             plex;
4939 
4940   PetscFunctionBegin;
4941   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4942   PetscCall(DMPforestGetPlex(dm,&plex));
4943   if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only;  /* maybe this should go into forest->plex */
4944   PetscCall(DMCreateMatrix(plex,mat));
4945   PetscCall(MatSetDM(*mat,dm));
4946   PetscFunctionReturn(0);
4947 }
4948 
4949 #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal)
4950 static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, InsertMode mode, Vec localX)
4951 {
4952   DM             plex;
4953 
4954   PetscFunctionBegin;
4955   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4956   PetscCall(DMPforestGetPlex(dm,&plex));
4957   PetscCall(DMProjectFunctionLocal(plex,time,funcs,ctxs,mode,localX));
4958   PetscFunctionReturn(0);
4959 }
4960 
4961 #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal)
4962 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)
4963 {
4964   DM             plex;
4965 
4966   PetscFunctionBegin;
4967   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4968   PetscCall(DMPforestGetPlex(dm,&plex));
4969   PetscCall(DMProjectFunctionLabelLocal(plex,time,label,numIds,ids,Ncc,comps,funcs,ctxs,mode,localX));
4970   PetscFunctionReturn(0);
4971 }
4972 
4973 #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal)
4974 PetscErrorCode DMProjectFieldLocal_pforest(DM dm, PetscReal time, Vec localU,void (**funcs) (PetscInt, PetscInt, PetscInt,
4975                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
4976                                                                              const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[],
4977                                                                              PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),InsertMode mode, Vec localX)
4978 {
4979   DM             plex;
4980 
4981   PetscFunctionBegin;
4982   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4983   PetscCall(DMPforestGetPlex(dm,&plex));
4984   PetscCall(DMProjectFieldLocal(plex,time,localU,funcs,mode,localX));
4985   PetscFunctionReturn(0);
4986 }
4987 
4988 #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff)
4989 PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal *diff)
4990 {
4991   DM             plex;
4992 
4993   PetscFunctionBegin;
4994   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
4995   PetscCall(DMPforestGetPlex(dm,&plex));
4996   PetscCall(DMComputeL2Diff(plex,time,funcs,ctxs,X,diff));
4997   PetscFunctionReturn(0);
4998 }
4999 
5000 #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff)
5001 PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal diff[])
5002 {
5003   DM             plex;
5004 
5005   PetscFunctionBegin;
5006   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5007   PetscCall(DMPforestGetPlex(dm,&plex));
5008   PetscCall(DMComputeL2FieldDiff(plex,time,funcs,ctxs,X,diff));
5009   PetscFunctionReturn(0);
5010 }
5011 
5012 #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection)
5013 static PetscErrorCode DMCreatelocalsection_pforest(DM dm)
5014 {
5015   DM             plex;
5016   PetscSection   section;
5017 
5018   PetscFunctionBegin;
5019   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5020   PetscCall(DMPforestGetPlex(dm,&plex));
5021   PetscCall(DMGetLocalSection(plex,&section));
5022   PetscCall(DMSetLocalSection(dm,section));
5023   PetscFunctionReturn(0);
5024 }
5025 
5026 #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints)
5027 static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm)
5028 {
5029   DM             plex;
5030   Mat            mat;
5031   Vec            bias;
5032   PetscSection   section;
5033 
5034   PetscFunctionBegin;
5035   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5036   PetscCall(DMPforestGetPlex(dm,&plex));
5037   PetscCall(DMGetDefaultConstraints(plex,&section,&mat,&bias));
5038   PetscCall(DMSetDefaultConstraints(dm,section,mat,bias));
5039   PetscFunctionReturn(0);
5040 }
5041 
5042 #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints)
5043 static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd)
5044 {
5045   DM             plex;
5046 
5047   PetscFunctionBegin;
5048   PetscValidHeaderSpecific(dm,DM_CLASSID,1);
5049   PetscCall(DMPforestGetPlex(dm,&plex));
5050   PetscCall(DMGetDimPoints(plex,dim,cStart,cEnd));
5051   PetscFunctionReturn(0);
5052 }
5053 
5054 /* Need to forward declare */
5055 #define DMInitialize_pforest _append_pforest(DMInitialize)
5056 static PetscErrorCode DMInitialize_pforest(DM dm);
5057 
5058 #define DMClone_pforest _append_pforest(DMClone)
5059 static PetscErrorCode DMClone_pforest(DM dm, DM *newdm)
5060 {
5061   PetscFunctionBegin;
5062   PetscCall(DMClone_Forest(dm,newdm));
5063   PetscCall(DMInitialize_pforest(*newdm));
5064   PetscFunctionReturn(0);
5065 }
5066 
5067 #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart)
5068 static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd)
5069 {
5070   DM_Forest         *forest;
5071   DM_Forest_pforest *pforest;
5072   PetscInt          overlap;
5073 
5074   PetscFunctionBegin;
5075   PetscCall(DMSetUp(dm));
5076   forest  = (DM_Forest*) dm->data;
5077   pforest = (DM_Forest_pforest*) forest->data;
5078   *cStart = 0;
5079   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
5080   if (overlap && pforest->ghost) {
5081     *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize];
5082   } else {
5083     *cEnd = pforest->forest->local_num_quadrants;
5084   }
5085   PetscFunctionReturn(0);
5086 }
5087 
5088 #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF)
5089 static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF)
5090 {
5091   DM_Forest         *forest;
5092   DM_Forest_pforest *pforest;
5093   PetscMPIInt       rank;
5094   PetscInt          overlap;
5095   PetscInt          cStart, cEnd, cLocalStart, cLocalEnd;
5096   PetscInt          nRoots, nLeaves, *mine = NULL;
5097   PetscSFNode       *remote = NULL;
5098   PetscSF           sf;
5099 
5100   PetscFunctionBegin;
5101   PetscCall(DMForestGetCellChart(dm,&cStart,&cEnd));
5102   forest      = (DM_Forest*)         dm->data;
5103   pforest     = (DM_Forest_pforest*) forest->data;
5104   nRoots      = cEnd - cStart;
5105   cLocalStart = pforest->cLocalStart;
5106   cLocalEnd   = pforest->cLocalEnd;
5107   nLeaves     = 0;
5108   PetscCall(DMForestGetPartitionOverlap(dm,&overlap));
5109   PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank));
5110   if (overlap && pforest->ghost) {
5111     PetscSFNode      *mirror;
5112     p4est_quadrant_t *mirror_array;
5113     PetscInt         nMirror, nGhostPre, nSelf, q;
5114     void             **mirrorPtrs;
5115 
5116     nMirror      = (PetscInt) pforest->ghost->mirrors.elem_count;
5117     nSelf        = cLocalEnd - cLocalStart;
5118     nLeaves      = nRoots - nSelf;
5119     nGhostPre    = (PetscInt) pforest->ghost->proc_offsets[rank];
5120     PetscCall(PetscMalloc1(nLeaves,&mine));
5121     PetscCall(PetscMalloc1(nLeaves,&remote));
5122     PetscCall(PetscMalloc2(nMirror,&mirror,nMirror,&mirrorPtrs));
5123     mirror_array = (p4est_quadrant_t*) pforest->ghost->mirrors.array;
5124     for (q = 0; q < nMirror; q++) {
5125       p4est_quadrant_t *mir = &(mirror_array[q]);
5126 
5127       mirror[q].rank  = rank;
5128       mirror[q].index = (PetscInt) mir->p.piggy3.local_num + cLocalStart;
5129       mirrorPtrs[q]   = (void*) &(mirror[q]);
5130     }
5131     PetscStackCallP4est(p4est_ghost_exchange_custom,(pforest->forest,pforest->ghost,sizeof(PetscSFNode),mirrorPtrs,remote));
5132     PetscCall(PetscFree2(mirror,mirrorPtrs));
5133     for (q = 0; q < nGhostPre; q++) mine[q] = q;
5134     for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd;
5135   }
5136   PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&sf));
5137   PetscCall(PetscSFSetGraph(sf,nRoots,nLeaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER));
5138   *cellSF = sf;
5139   PetscFunctionReturn(0);
5140 }
5141 
5142 static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS* ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void*), void **setup_ctx)
5143 {
5144   DM             plex;
5145 
5146   PetscFunctionBegin;
5147   PetscCall(DMPforestGetPlex(dm,&plex));
5148   PetscCall(DMCreateNeumannOverlap_Plex(plex,ovl,J,setup,setup_ctx));
5149   if (!*setup) {
5150     PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup));
5151     if (*setup) {
5152       PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm));
5153     }
5154   }
5155   PetscFunctionReturn(0);
5156 }
5157 
5158 static PetscErrorCode DMInitialize_pforest(DM dm)
5159 {
5160   PetscFunctionBegin;
5161   dm->ops->setup                     = DMSetUp_pforest;
5162   dm->ops->view                      = DMView_pforest;
5163   dm->ops->clone                     = DMClone_pforest;
5164   dm->ops->createinterpolation       = DMCreateInterpolation_pforest;
5165   dm->ops->createinjection           = DMCreateInjection_pforest;
5166   dm->ops->setfromoptions            = DMSetFromOptions_pforest;
5167   dm->ops->createcoordinatedm        = DMCreateCoordinateDM_pforest;
5168   dm->ops->createglobalvector        = DMCreateGlobalVector_pforest;
5169   dm->ops->createlocalvector         = DMCreateLocalVector_pforest;
5170   dm->ops->creatematrix              = DMCreateMatrix_pforest;
5171   dm->ops->projectfunctionlocal      = DMProjectFunctionLocal_pforest;
5172   dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest;
5173   dm->ops->projectfieldlocal         = DMProjectFieldLocal_pforest;
5174   dm->ops->createlocalsection        = DMCreatelocalsection_pforest;
5175   dm->ops->createdefaultconstraints  = DMCreateDefaultConstraints_pforest;
5176   dm->ops->computel2diff             = DMComputeL2Diff_pforest;
5177   dm->ops->computel2fielddiff        = DMComputeL2FieldDiff_pforest;
5178   dm->ops->getdimpoints              = DMGetDimPoints_pforest;
5179 
5180   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",DMConvert_plex_pforest));
5181   PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",DMConvert_pforest_plex));
5182   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_pforest));
5183   PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMForestGetPartitionOverlap));
5184   PetscFunctionReturn(0);
5185 }
5186 
5187 #define DMCreate_pforest _append_pforest(DMCreate)
5188 PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm)
5189 {
5190   DM_Forest         *forest;
5191   DM_Forest_pforest *pforest;
5192 
5193   PetscFunctionBegin;
5194   PetscCall(PetscP4estInitialize());
5195   PetscCall(DMCreate_Forest(dm));
5196   PetscCall(DMInitialize_pforest(dm));
5197   PetscCall(DMSetDimension(dm,P4EST_DIM));
5198 
5199   /* set forest defaults */
5200   PetscCall(DMForestSetTopology(dm,"unit"));
5201   PetscCall(DMForestSetMinimumRefinement(dm,0));
5202   PetscCall(DMForestSetInitialRefinement(dm,0));
5203   PetscCall(DMForestSetMaximumRefinement(dm,P4EST_QMAXLEVEL));
5204   PetscCall(DMForestSetGradeFactor(dm,2));
5205   PetscCall(DMForestSetAdjacencyDimension(dm,0));
5206   PetscCall(DMForestSetPartitionOverlap(dm,0));
5207 
5208   /* create p4est data */
5209   PetscCall(PetscNewLog(dm,&pforest));
5210 
5211   forest                            = (DM_Forest*) dm->data;
5212   forest->data                      = pforest;
5213   forest->destroy                   = DMForestDestroy_pforest;
5214   forest->ftemplate                 = DMForestTemplate_pforest;
5215   forest->transfervec               = DMForestTransferVec_pforest;
5216   forest->transfervecfrombase       = DMForestTransferVecFromBase_pforest;
5217   forest->createcellchart           = DMForestCreateCellChart_pforest;
5218   forest->createcellsf              = DMForestCreateCellSF_pforest;
5219   forest->clearadaptivityforest     = DMForestClearAdaptivityForest_pforest;
5220   forest->getadaptivitysuccess      = DMForestGetAdaptivitySuccess_pforest;
5221   pforest->topo                     = NULL;
5222   pforest->forest                   = NULL;
5223   pforest->ghost                    = NULL;
5224   pforest->lnodes                   = NULL;
5225   pforest->partition_for_coarsening = PETSC_TRUE;
5226   pforest->coarsen_hierarchy        = PETSC_FALSE;
5227   pforest->cLocalStart              = -1;
5228   pforest->cLocalEnd                = -1;
5229   pforest->labelsFinalized          = PETSC_FALSE;
5230   pforest->ghostName                = NULL;
5231   PetscFunctionReturn(0);
5232 }
5233 
5234 #endif /* defined(PETSC_HAVE_P4EST) */
5235