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