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