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