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