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