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