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