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