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