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