1 #include <petscds.h> 2 #include <petsc/private/dmimpl.h> 3 #include <petsc/private/dmforestimpl.h> 4 #include <petsc/private/dmpleximpl.h> 5 #include <petsc/private/dmlabelimpl.h> 6 #include <petsc/private/viewerimpl.h> 7 #include <../src/sys/classes/viewer/impls/vtk/vtkvimpl.h> 8 #include "petsc_p4est_package.h" 9 10 #if defined(PETSC_HAVE_P4EST) 11 12 #if !defined(P4_TO_P8) 13 #include <p4est.h> 14 #include <p4est_extended.h> 15 #include <p4est_geometry.h> 16 #include <p4est_ghost.h> 17 #include <p4est_lnodes.h> 18 #include <p4est_vtk.h> 19 #include <p4est_plex.h> 20 #include <p4est_bits.h> 21 #include <p4est_algorithms.h> 22 #else 23 #include <p8est.h> 24 #include <p8est_extended.h> 25 #include <p8est_geometry.h> 26 #include <p8est_ghost.h> 27 #include <p8est_lnodes.h> 28 #include <p8est_vtk.h> 29 #include <p8est_plex.h> 30 #include <p8est_bits.h> 31 #include <p8est_algorithms.h> 32 #endif 33 34 typedef enum {PATTERN_HASH,PATTERN_FRACTAL,PATTERN_CORNER,PATTERN_CENTER,PATTERN_COUNT} DMRefinePattern; 35 static const char *DMRefinePatternName[PATTERN_COUNT] = {"hash","fractal","corner","center"}; 36 37 typedef struct _DMRefinePatternCtx 38 { 39 PetscInt corner; 40 PetscBool fractal[P4EST_CHILDREN]; 41 PetscReal hashLikelihood; 42 PetscInt maxLevel; 43 p4est_refine_t refine_fn; 44 } 45 DMRefinePatternCtx; 46 47 static int DMRefinePattern_Corner(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) 48 { 49 p4est_quadrant_t root, rootcorner; 50 DMRefinePatternCtx *ctx; 51 52 ctx = (DMRefinePatternCtx*) p4est->user_pointer; 53 if (quadrant->level >= ctx->maxLevel) return 0; 54 55 root.x = root.y = 0; 56 #if defined(P4_TO_P8) 57 root.z = 0; 58 #endif 59 root.level = 0; 60 p4est_quadrant_corner_descendant(&root,&rootcorner,ctx->corner,quadrant->level); 61 if (p4est_quadrant_is_equal(quadrant,&rootcorner)) return 1; 62 return 0; 63 } 64 65 static int DMRefinePattern_Center(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) 66 { 67 int cid; 68 p4est_quadrant_t ancestor, ancestorcorner; 69 DMRefinePatternCtx *ctx; 70 71 ctx = (DMRefinePatternCtx*) p4est->user_pointer; 72 if (quadrant->level >= ctx->maxLevel) return 0; 73 if (quadrant->level <= 1) return 1; 74 75 p4est_quadrant_ancestor(quadrant,1,&ancestor); 76 cid = p4est_quadrant_child_id(&ancestor); 77 p4est_quadrant_corner_descendant(&ancestor,&ancestorcorner,P4EST_CHILDREN - 1 - cid,quadrant->level); 78 if (p4est_quadrant_is_equal(quadrant,&ancestorcorner)) return 1; 79 return 0; 80 } 81 82 static int DMRefinePattern_Fractal(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) 83 { 84 int cid; 85 DMRefinePatternCtx *ctx; 86 87 ctx = (DMRefinePatternCtx*) p4est->user_pointer; 88 if (quadrant->level >= ctx->maxLevel) return 0; 89 if (!quadrant->level) return 1; 90 cid = p4est_quadrant_child_id(quadrant); 91 if (ctx->fractal[cid ^ ((int) (quadrant->level % P4EST_CHILDREN))]) return 1; 92 return 0; 93 } 94 95 /* simplified from MurmurHash3 by Austin Appleby */ 96 #define DMPROT32(x, y) ((x << y) | (x >> (32 - y))) 97 static uint32_t DMPforestHash(const uint32_t *blocks, uint32_t nblocks) 98 { 99 uint32_t c1 = 0xcc9e2d51; 100 uint32_t c2 = 0x1b873593; 101 uint32_t r1 = 15; 102 uint32_t r2 = 13; 103 uint32_t m = 5; 104 uint32_t n = 0xe6546b64; 105 uint32_t hash = 0; 106 int len = nblocks * 4; 107 uint32_t i; 108 109 for (i = 0; i < nblocks; i++) { 110 uint32_t k; 111 112 k = blocks[i]; 113 k *= c1; 114 k = DMPROT32(k, r1); 115 k *= c2; 116 117 hash ^= k; 118 hash = DMPROT32(hash, r2) * m + n; 119 } 120 121 hash ^= len; 122 hash ^= (hash >> 16); 123 hash *= 0x85ebca6b; 124 hash ^= (hash >> 13); 125 hash *= 0xc2b2ae35; 126 hash ^= (hash >> 16); 127 128 return hash; 129 } 130 131 #if defined(UINT32_MAX) 132 #define DMP4EST_HASH_MAX UINT32_MAX 133 #else 134 #define DMP4EST_HASH_MAX ((uint32_t) 0xffffffff) 135 #endif 136 137 static int DMRefinePattern_Hash(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) 138 { 139 uint32_t data[5]; 140 uint32_t result; 141 DMRefinePatternCtx *ctx; 142 143 ctx = (DMRefinePatternCtx*) p4est->user_pointer; 144 if (quadrant->level >= ctx->maxLevel) return 0; 145 data[0] = ((uint32_t) quadrant->level) << 24; 146 data[1] = (uint32_t) which_tree; 147 data[2] = (uint32_t) quadrant->x; 148 data[3] = (uint32_t) quadrant->y; 149 #if defined(P4_TO_P8) 150 data[4] = (uint32_t) quadrant->z; 151 #endif 152 153 result = DMPforestHash(data,2+P4EST_DIM); 154 if (((double) result / (double) DMP4EST_HASH_MAX) < ctx->hashLikelihood) return 1; 155 return 0; 156 } 157 158 #define DMConvert_pforest_plex _infix_pforest(DMConvert,_plex) 159 static PetscErrorCode DMConvert_pforest_plex(DM,DMType,DM*); 160 161 #define DMFTopology_pforest _append_pforest(DMFTopology) 162 typedef struct { 163 PetscInt refct; 164 p4est_connectivity_t *conn; 165 p4est_geometry_t *geom; 166 PetscInt *tree_face_to_uniq; /* p4est does not explicitly enumerate facets, but we must to keep track of labels */ 167 } DMFTopology_pforest; 168 169 #define DM_Forest_pforest _append_pforest(DM_Forest) 170 typedef struct { 171 DMFTopology_pforest *topo; 172 p4est_t *forest; 173 p4est_ghost_t *ghost; 174 p4est_lnodes_t *lnodes; 175 PetscBool partition_for_coarsening; 176 PetscBool coarsen_hierarchy; 177 PetscBool labelsFinalized; 178 PetscBool adaptivitySuccess; 179 PetscInt cLocalStart; 180 PetscInt cLocalEnd; 181 DM plex; 182 char *ghostName; 183 PetscSF pointAdaptToSelfSF; 184 PetscSF pointSelfToAdaptSF; 185 PetscInt *pointAdaptToSelfCids; 186 PetscInt *pointSelfToAdaptCids; 187 } DM_Forest_pforest; 188 189 #define DM_Forest_geometry_pforest _append_pforest(DM_Forest_geometry) 190 typedef struct { 191 DM base; 192 PetscErrorCode (*map)(DM, PetscInt, PetscInt, const PetscReal[], PetscReal[], void*); 193 void *mapCtx; 194 PetscInt coordDim; 195 p4est_geometry_t *inner; 196 } 197 DM_Forest_geometry_pforest; 198 199 #define GeometryMapping_pforest _append_pforest(GeometryMapping) 200 static void GeometryMapping_pforest(p4est_geometry_t *geom, p4est_topidx_t which_tree, const double abc[3], double xyz[3]) 201 { 202 DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user; 203 PetscReal PetscABC[3] = {0.}; 204 PetscReal PetscXYZ[3] = {0.}; 205 PetscInt i, d = PetscMin(3,geom_pforest->coordDim); 206 double ABC[3]; 207 PetscErrorCode ierr; 208 209 (geom_pforest->inner->X)(geom_pforest->inner,which_tree,abc,ABC); 210 211 for (i = 0; i < d; i++) PetscABC[i] = ABC[i]; 212 ierr = (geom_pforest->map)(geom_pforest->base,(PetscInt) which_tree,geom_pforest->coordDim,PetscABC,PetscXYZ,geom_pforest->mapCtx);PETSC_P4EST_ASSERT(!ierr); 213 for (i = 0; i < d; i++) xyz[i] = PetscXYZ[i]; 214 } 215 216 #define GeometryDestroy_pforest _append_pforest(GeometryDestroy) 217 static void GeometryDestroy_pforest(p4est_geometry_t *geom) 218 { 219 DM_Forest_geometry_pforest *geom_pforest = (DM_Forest_geometry_pforest*)geom->user; 220 PetscErrorCode ierr; 221 222 p4est_geometry_destroy(geom_pforest->inner); 223 ierr = PetscFree(geom->user);PETSC_P4EST_ASSERT(!ierr); 224 ierr = PetscFree(geom);PETSC_P4EST_ASSERT(!ierr); 225 } 226 227 #define DMFTopologyDestroy_pforest _append_pforest(DMFTopologyDestroy) 228 static PetscErrorCode DMFTopologyDestroy_pforest(DMFTopology_pforest **topo) 229 { 230 PetscFunctionBegin; 231 if (!(*topo)) PetscFunctionReturn(0); 232 if (--((*topo)->refct) > 0) { 233 *topo = NULL; 234 PetscFunctionReturn(0); 235 } 236 if ((*topo)->geom) PetscStackCallP4est(p4est_geometry_destroy,((*topo)->geom)); 237 PetscStackCallP4est(p4est_connectivity_destroy,((*topo)->conn)); 238 PetscCall(PetscFree((*topo)->tree_face_to_uniq)); 239 PetscCall(PetscFree(*topo)); 240 *topo = NULL; 241 PetscFunctionReturn(0); 242 } 243 244 static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t*,PetscInt**); 245 246 #define DMFTopologyCreateBrick_pforest _append_pforest(DMFTopologyCreateBrick) 247 static PetscErrorCode DMFTopologyCreateBrick_pforest(DM dm,PetscInt N[], PetscInt P[], PetscReal B[],DMFTopology_pforest **topo, PetscBool useMorton) 248 { 249 double *vertices; 250 PetscInt i, numVerts; 251 252 PetscFunctionBegin; 253 PetscCheck(useMorton,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Lexicographic ordering not implemented yet"); 254 PetscCall(PetscNewLog(dm,topo)); 255 256 (*topo)->refct = 1; 257 #if !defined(P4_TO_P8) 258 PetscStackCallP4estReturn((*topo)->conn,p4est_connectivity_new_brick,((int) N[0], (int) N[1], (P[0] == DM_BOUNDARY_NONE) ? 0 : 1, (P[1] == DM_BOUNDARY_NONE) ? 0 : 1)); 259 #else 260 PetscStackCallP4estReturn((*topo)->conn,p8est_connectivity_new_brick,((int) N[0], (int) N[1], (int) N[2], (P[0] == DM_BOUNDARY_NONE) ? 0 : 1, (P[1] == DM_BOUNDARY_NONE) ? 0 : 1, (P[2] == DM_BOUNDARY_NONE) ? 0 : 1)); 261 #endif 262 numVerts = (*topo)->conn->num_vertices; 263 vertices = (*topo)->conn->vertices; 264 for (i = 0; i < 3 * numVerts; i++) { 265 PetscInt j = i % 3; 266 267 vertices[i] = B[2 * j] + (vertices[i]/N[j]) * (B[2 * j + 1] - B[2 * j]); 268 } 269 (*topo)->geom = NULL; 270 PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq)); 271 PetscFunctionReturn(0); 272 } 273 274 #define DMFTopologyCreate_pforest _append_pforest(DMFTopologyCreate) 275 static PetscErrorCode DMFTopologyCreate_pforest(DM dm, DMForestTopology topologyName, DMFTopology_pforest **topo) 276 { 277 const char *name = (const char*) topologyName; 278 const char *prefix; 279 PetscBool isBrick, isShell, isSphere, isMoebius; 280 281 PetscFunctionBegin; 282 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 283 PetscValidCharPointer(name,2); 284 PetscValidPointer(topo,3); 285 PetscCall(PetscStrcmp(name,"brick",&isBrick)); 286 PetscCall(PetscStrcmp(name,"shell",&isShell)); 287 PetscCall(PetscStrcmp(name,"sphere",&isSphere)); 288 PetscCall(PetscStrcmp(name,"moebius",&isMoebius)); 289 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix)); 290 if (isBrick) { 291 PetscBool flgN, flgP, flgM, flgB, useMorton = PETSC_TRUE, periodic = PETSC_FALSE; 292 PetscInt N[3] = {2,2,2}, P[3] = {0,0,0}, nretN = P4EST_DIM, nretP = P4EST_DIM, nretB = 2 * P4EST_DIM, i; 293 PetscReal B[6] = {0.0,1.0,0.0,1.0,0.0,1.0}; 294 295 if (dm->setfromoptionscalled) { 296 PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_size",N,&nretN,&flgN)); 297 PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_periodicity",P,&nretP,&flgP)); 298 PetscCall(PetscOptionsGetRealArray(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_bounds",B,&nretB,&flgB)); 299 PetscCall(PetscOptionsGetBool(((PetscObject)dm)->options,prefix,"-dm_p4est_brick_use_morton_curve",&useMorton,&flgM)); 300 PetscCheck(!flgN || nretN == P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d sizes in -dm_p4est_brick_size, gave %" PetscInt_FMT,P4EST_DIM,nretN); 301 PetscCheck(!flgP || nretP == P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d periodicities in -dm_p4est_brick_periodicity, gave %" PetscInt_FMT,P4EST_DIM,nretP); 302 PetscCheck(!flgB || nretB == 2 * P4EST_DIM,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_SIZ,"Need to give %d bounds in -dm_p4est_brick_bounds, gave %" PetscInt_FMT,P4EST_DIM,nretP); 303 } 304 for (i = 0; i < P4EST_DIM; i++) { 305 P[i] = (P[i] ? DM_BOUNDARY_PERIODIC : DM_BOUNDARY_NONE); 306 periodic = (PetscBool)(P[i] || periodic); 307 if (!flgB) B[2 * i + 1] = N[i]; 308 } 309 PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,B,topo,useMorton)); 310 /* the maxCell trick is not robust enough, localize on all cells if periodic */ 311 PetscCall(DMSetPeriodicity(dm,periodic,NULL,NULL,NULL)); 312 } else { 313 PetscCall(PetscNewLog(dm,topo)); 314 315 (*topo)->refct = 1; 316 PetscStackCallP4estReturn((*topo)->conn,p4est_connectivity_new_byname,(name)); 317 (*topo)->geom = NULL; 318 if (isMoebius) PetscCall(DMSetCoordinateDim(dm,3)); 319 #if defined(P4_TO_P8) 320 if (isShell) { 321 PetscReal R2 = 1., R1 = .55; 322 323 if (dm->setfromoptionscalled) { 324 PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_outer_radius",&R2,NULL)); 325 PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_shell_inner_radius",&R1,NULL)); 326 } 327 PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_shell,((*topo)->conn,R2,R1)); 328 } else if (isSphere) { 329 PetscReal R2 = 1., R1 = 0.191728, R0 = 0.039856; 330 331 if (dm->setfromoptionscalled) { 332 PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_outer_radius",&R2,NULL)); 333 PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_inner_radius",&R1,NULL)); 334 PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_sphere_core_radius",&R0,NULL)); 335 } 336 PetscStackCallP4estReturn((*topo)->geom,p8est_geometry_new_sphere,((*topo)->conn,R2,R1,R0)); 337 } 338 #endif 339 PetscCall(PforestConnectivityEnumerateFacets((*topo)->conn,&(*topo)->tree_face_to_uniq)); 340 } 341 PetscFunctionReturn(0); 342 } 343 344 #define DMConvert_plex_pforest _append_pforest(DMConvert_plex) 345 static PetscErrorCode DMConvert_plex_pforest(DM dm, DMType newtype, DM *pforest) 346 { 347 MPI_Comm comm; 348 PetscBool isPlex; 349 PetscInt dim; 350 void *ctx; 351 352 PetscFunctionBegin; 353 354 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 355 comm = PetscObjectComm((PetscObject)dm); 356 PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPLEX,&isPlex)); 357 PetscCheck(isPlex,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPLEX,((PetscObject)dm)->type_name); 358 PetscCall(DMGetDimension(dm,&dim)); 359 PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim); 360 PetscCall(DMCreate(comm,pforest)); 361 PetscCall(DMSetType(*pforest,DMPFOREST)); 362 PetscCall(DMForestSetBaseDM(*pforest,dm)); 363 PetscCall(DMGetApplicationContext(dm,&ctx)); 364 PetscCall(DMSetApplicationContext(*pforest,ctx)); 365 PetscCall(DMCopyDisc(dm,*pforest)); 366 PetscFunctionReturn(0); 367 } 368 369 #define DMForestDestroy_pforest _append_pforest(DMForestDestroy) 370 static PetscErrorCode DMForestDestroy_pforest(DM dm) 371 { 372 DM_Forest *forest = (DM_Forest*) dm->data; 373 DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data; 374 375 PetscFunctionBegin; 376 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 377 if (pforest->lnodes) PetscStackCallP4est(p4est_lnodes_destroy,(pforest->lnodes)); 378 pforest->lnodes = NULL; 379 if (pforest->ghost) PetscStackCallP4est(p4est_ghost_destroy,(pforest->ghost)); 380 pforest->ghost = NULL; 381 if (pforest->forest) PetscStackCallP4est(p4est_destroy,(pforest->forest)); 382 pforest->forest = NULL; 383 PetscCall(DMFTopologyDestroy_pforest(&pforest->topo)); 384 PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",NULL)); 385 PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",NULL)); 386 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMSetUpGLVisViewer_C",NULL)); 387 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",NULL)); 388 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",NULL)); 389 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"MatComputeNeumannOverlap_C",NULL)); 390 PetscCall(PetscFree(pforest->ghostName)); 391 PetscCall(DMDestroy(&pforest->plex)); 392 PetscCall(PetscSFDestroy(&pforest->pointAdaptToSelfSF)); 393 PetscCall(PetscSFDestroy(&pforest->pointSelfToAdaptSF)); 394 PetscCall(PetscFree(pforest->pointAdaptToSelfCids)); 395 PetscCall(PetscFree(pforest->pointSelfToAdaptCids)); 396 PetscCall(PetscFree(forest->data)); 397 PetscFunctionReturn(0); 398 } 399 400 #define DMForestTemplate_pforest _append_pforest(DMForestTemplate) 401 static PetscErrorCode DMForestTemplate_pforest(DM dm, DM tdm) 402 { 403 DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data; 404 DM_Forest_pforest *tpforest = (DM_Forest_pforest*) ((DM_Forest*) tdm->data)->data; 405 406 PetscFunctionBegin; 407 if (pforest->topo) pforest->topo->refct++; 408 PetscCall(DMFTopologyDestroy_pforest(&(tpforest->topo))); 409 tpforest->topo = pforest->topo; 410 PetscFunctionReturn(0); 411 } 412 413 #define DMPlexCreateConnectivity_pforest _append_pforest(DMPlexCreateConnectivity) 414 static PetscErrorCode DMPlexCreateConnectivity_pforest(DM,p4est_connectivity_t**,PetscInt**); 415 416 typedef struct _PforestAdaptCtx 417 { 418 PetscInt maxLevel; 419 PetscInt minLevel; 420 PetscInt currLevel; 421 PetscBool anyChange; 422 } 423 PforestAdaptCtx; 424 425 static int pforest_coarsen_currlevel(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[]) 426 { 427 PforestAdaptCtx *ctx = (PforestAdaptCtx*) p4est->user_pointer; 428 PetscInt minLevel = ctx->minLevel; 429 PetscInt currLevel = ctx->currLevel; 430 431 if (quadrants[0]->level <= minLevel) return 0; 432 return (int) ((PetscInt) quadrants[0]->level == currLevel); 433 } 434 435 static int pforest_coarsen_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[]) 436 { 437 PforestAdaptCtx *ctx = (PforestAdaptCtx*) p4est->user_pointer; 438 PetscInt minLevel = ctx->minLevel; 439 440 return (int) ((PetscInt) quadrants[0]->level > minLevel); 441 } 442 443 static int pforest_coarsen_flag_any(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[]) 444 { 445 PetscInt i; 446 PetscBool any = PETSC_FALSE; 447 PforestAdaptCtx *ctx = (PforestAdaptCtx*) p4est->user_pointer; 448 PetscInt minLevel = ctx->minLevel; 449 450 if (quadrants[0]->level <= minLevel) return 0; 451 for (i = 0; i < P4EST_CHILDREN; i++) { 452 if (quadrants[i]->p.user_int == DM_ADAPT_KEEP) { 453 any = PETSC_FALSE; 454 break; 455 } 456 if (quadrants[i]->p.user_int == DM_ADAPT_COARSEN) { 457 any = PETSC_TRUE; 458 break; 459 } 460 } 461 return any ? 1 : 0; 462 } 463 464 static int pforest_coarsen_flag_all(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrants[]) 465 { 466 PetscInt i; 467 PetscBool all = PETSC_TRUE; 468 PforestAdaptCtx *ctx = (PforestAdaptCtx*) p4est->user_pointer; 469 PetscInt minLevel = ctx->minLevel; 470 471 if (quadrants[0]->level <= minLevel) return 0; 472 for (i = 0; i < P4EST_CHILDREN; i++) { 473 if (quadrants[i]->p.user_int != DM_ADAPT_COARSEN) { 474 all = PETSC_FALSE; 475 break; 476 } 477 } 478 return all ? 1 : 0; 479 } 480 481 static void pforest_init_determine(p4est_t *p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) 482 { 483 quadrant->p.user_int = DM_ADAPT_DETERMINE; 484 } 485 486 static int pforest_refine_uniform(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) 487 { 488 PforestAdaptCtx *ctx = (PforestAdaptCtx*) p4est->user_pointer; 489 PetscInt maxLevel = ctx->maxLevel; 490 491 return ((PetscInt) quadrant->level < maxLevel); 492 } 493 494 static int pforest_refine_flag(p4est_t * p4est, p4est_topidx_t which_tree, p4est_quadrant_t *quadrant) 495 { 496 PforestAdaptCtx *ctx = (PforestAdaptCtx*) p4est->user_pointer; 497 PetscInt maxLevel = ctx->maxLevel; 498 499 if ((PetscInt) quadrant->level >= maxLevel) return 0; 500 501 return (quadrant->p.user_int == DM_ADAPT_REFINE); 502 } 503 504 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) 505 { 506 PetscMPIInt rank = p4estFrom->mpirank; 507 p4est_topidx_t t; 508 PetscInt toFineLeaves = 0, fromFineLeaves = 0; 509 510 PetscFunctionBegin; 511 for (t = flt; t <= llt; t++) { /* count roots and leaves */ 512 p4est_tree_t *treeFrom = &(((p4est_tree_t*) p4estFrom->trees->array)[t]); 513 p4est_tree_t *treeTo = &(((p4est_tree_t*) p4estTo->trees->array)[t]); 514 p4est_quadrant_t *firstFrom = &treeFrom->first_desc; 515 p4est_quadrant_t *firstTo = &treeTo->first_desc; 516 PetscInt numFrom = (PetscInt) treeFrom->quadrants.elem_count; 517 PetscInt numTo = (PetscInt) treeTo->quadrants.elem_count; 518 p4est_quadrant_t *quadsFrom = (p4est_quadrant_t*) treeFrom->quadrants.array; 519 p4est_quadrant_t *quadsTo = (p4est_quadrant_t*) treeTo->quadrants.array; 520 PetscInt currentFrom, currentTo; 521 PetscInt treeOffsetFrom = (PetscInt) treeFrom->quadrants_offset; 522 PetscInt treeOffsetTo = (PetscInt) treeTo->quadrants_offset; 523 int comp; 524 525 PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(firstFrom,firstTo)); 526 PetscCheck(comp,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"non-matching partitions"); 527 528 for (currentFrom = 0, currentTo = 0; currentFrom < numFrom && currentTo < numTo;) { 529 p4est_quadrant_t *quadFrom = &quadsFrom[currentFrom]; 530 p4est_quadrant_t *quadTo = &quadsTo[currentTo]; 531 532 if (quadFrom->level == quadTo->level) { 533 if (toLeaves) { 534 toLeaves[toFineLeaves] = currentTo + treeOffsetTo + ToOffset; 535 fromRoots[toFineLeaves].rank = rank; 536 fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset; 537 } 538 toFineLeaves++; 539 currentFrom++; 540 currentTo++; 541 } else { 542 int fromIsAncestor; 543 544 PetscStackCallP4estReturn(fromIsAncestor,p4est_quadrant_is_ancestor,(quadFrom,quadTo)); 545 if (fromIsAncestor) { 546 p4est_quadrant_t lastDesc; 547 548 if (toLeaves) { 549 toLeaves[toFineLeaves] = currentTo + treeOffsetTo + ToOffset; 550 fromRoots[toFineLeaves].rank = rank; 551 fromRoots[toFineLeaves].index = currentFrom + treeOffsetFrom + FromOffset; 552 } 553 toFineLeaves++; 554 currentTo++; 555 PetscStackCallP4est(p4est_quadrant_last_descendant,(quadFrom,&lastDesc,quadTo->level)); 556 PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadTo,&lastDesc)); 557 if (comp) currentFrom++; 558 } else { 559 p4est_quadrant_t lastDesc; 560 561 if (fromLeaves) { 562 fromLeaves[fromFineLeaves] = currentFrom + treeOffsetFrom + FromOffset; 563 toRoots[fromFineLeaves].rank = rank; 564 toRoots[fromFineLeaves].index = currentTo + treeOffsetTo + ToOffset; 565 } 566 fromFineLeaves++; 567 currentFrom++; 568 PetscStackCallP4est(p4est_quadrant_last_descendant,(quadTo,&lastDesc,quadFrom->level)); 569 PetscStackCallP4estReturn(comp,p4est_quadrant_is_equal,(quadFrom,&lastDesc)); 570 if (comp) currentTo++; 571 } 572 } 573 } 574 } 575 *toFineLeavesCount = toFineLeaves; 576 *fromFineLeavesCount = fromFineLeaves; 577 PetscFunctionReturn(0); 578 } 579 580 /* Compute the maximum level across all the trees */ 581 static PetscErrorCode DMPforestGetRefinementLevel(DM dm, PetscInt *lev) 582 { 583 p4est_topidx_t t, flt, llt; 584 DM_Forest *forest = (DM_Forest*) dm->data; 585 DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data; 586 PetscInt maxlevelloc = 0; 587 p4est_t *p4est; 588 589 PetscFunctionBegin; 590 PetscCheck(pforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing DM_Forest_pforest"); 591 PetscCheck(pforest->forest,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Missing p4est_t"); 592 p4est = pforest->forest; 593 flt = p4est->first_local_tree; 594 llt = p4est->last_local_tree; 595 for (t = flt; t <= llt; t++) { 596 p4est_tree_t *tree = &(((p4est_tree_t*) p4est->trees->array)[t]); 597 maxlevelloc = PetscMax((PetscInt)tree->maxlevel,maxlevelloc); 598 } 599 PetscCall(MPIU_Allreduce(&maxlevelloc,lev,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 600 PetscFunctionReturn(0); 601 } 602 603 /* Puts identity in coarseToFine */ 604 /* assumes a matching partition */ 605 static PetscErrorCode DMPforestComputeLocalCellTransferSF(MPI_Comm comm, p4est_t *p4estFrom, PetscInt FromOffset, p4est_t *p4estTo, PetscInt ToOffset, PetscSF *fromCoarseToFine, PetscSF *toCoarseFromFine) 606 { 607 p4est_topidx_t flt, llt; 608 PetscSF fromCoarse, toCoarse; 609 PetscInt numRootsFrom, numRootsTo, numLeavesFrom, numLeavesTo; 610 PetscInt *fromLeaves = NULL, *toLeaves = NULL; 611 PetscSFNode *fromRoots = NULL, *toRoots = NULL; 612 613 PetscFunctionBegin; 614 flt = p4estFrom->first_local_tree; 615 llt = p4estFrom->last_local_tree; 616 PetscCall(PetscSFCreate(comm,&fromCoarse)); 617 if (toCoarseFromFine) { 618 PetscCall(PetscSFCreate(comm,&toCoarse)); 619 } 620 numRootsFrom = p4estFrom->local_num_quadrants + FromOffset; 621 numRootsTo = p4estTo->local_num_quadrants + ToOffset; 622 PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,NULL,NULL,&numLeavesFrom,NULL,NULL)); 623 PetscCall(PetscMalloc1(numLeavesTo,&toLeaves)); 624 PetscCall(PetscMalloc1(numLeavesTo,&fromRoots)); 625 if (toCoarseFromFine) { 626 PetscCall(PetscMalloc1(numLeavesFrom,&fromLeaves)); 627 PetscCall(PetscMalloc1(numLeavesFrom,&fromRoots)); 628 } 629 PetscCall(DMPforestComputeLocalCellTransferSF_loop(p4estFrom,FromOffset,p4estTo,ToOffset,flt,llt,&numLeavesTo,toLeaves,fromRoots,&numLeavesFrom,fromLeaves,toRoots)); 630 if (!ToOffset && (numLeavesTo == numRootsTo)) { /* compress */ 631 PetscCall(PetscFree(toLeaves)); 632 PetscCall(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,NULL,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER)); 633 } else PetscCall(PetscSFSetGraph(fromCoarse,numRootsFrom,numLeavesTo,toLeaves,PETSC_OWN_POINTER,fromRoots,PETSC_OWN_POINTER)); 634 *fromCoarseToFine = fromCoarse; 635 if (toCoarseFromFine) { 636 PetscCall(PetscSFSetGraph(toCoarse,numRootsTo,numLeavesFrom,fromLeaves,PETSC_OWN_POINTER,toRoots,PETSC_OWN_POINTER)); 637 *toCoarseFromFine = toCoarse; 638 } 639 PetscFunctionReturn(0); 640 } 641 642 /* range of processes whose B sections overlap this ranks A section */ 643 static PetscErrorCode DMPforestComputeOverlappingRanks(PetscMPIInt size, PetscMPIInt rank, p4est_t *p4estA, p4est_t *p4estB, PetscInt *startB, PetscInt *endB) 644 { 645 p4est_quadrant_t * myCoarseStart = &(p4estA->global_first_position[rank]); 646 p4est_quadrant_t * myCoarseEnd = &(p4estA->global_first_position[rank+1]); 647 p4est_quadrant_t * globalFirstB = p4estB->global_first_position; 648 649 PetscFunctionBegin; 650 *startB = -1; 651 *endB = -1; 652 if (p4estA->local_num_quadrants) { 653 PetscInt lo, hi, guess; 654 /* binary search to find interval containing myCoarseStart */ 655 lo = 0; 656 hi = size; 657 guess = rank; 658 while (1) { 659 int startCompMy, myCompEnd; 660 661 PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseStart)); 662 PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseStart,&globalFirstB[guess+1])); 663 if (startCompMy <= 0 && myCompEnd < 0) { 664 *startB = guess; 665 break; 666 } else if (startCompMy > 0) { /* guess is to high */ 667 hi = guess; 668 } else { /* guess is to low */ 669 lo = guess + 1; 670 } 671 guess = lo + (hi - lo) / 2; 672 } 673 /* reset bounds, but not guess */ 674 lo = 0; 675 hi = size; 676 while (1) { 677 int startCompMy, myCompEnd; 678 679 PetscStackCallP4estReturn(startCompMy,p4est_quadrant_compare_piggy,(&globalFirstB[guess],myCoarseEnd)); 680 PetscStackCallP4estReturn(myCompEnd,p4est_quadrant_compare_piggy,(myCoarseEnd,&globalFirstB[guess+1])); 681 if (startCompMy < 0 && myCompEnd <= 0) { /* notice that the comparison operators are different from above */ 682 *endB = guess + 1; 683 break; 684 } else if (startCompMy >= 0) { /* guess is to high */ 685 hi = guess; 686 } else { /* guess is to low */ 687 lo = guess + 1; 688 } 689 guess = lo + (hi - lo) / 2; 690 } 691 } 692 PetscFunctionReturn(0); 693 } 694 695 static PetscErrorCode DMPforestGetPlex(DM,DM*); 696 697 #define DMSetUp_pforest _append_pforest(DMSetUp) 698 static PetscErrorCode DMSetUp_pforest(DM dm) 699 { 700 DM_Forest *forest = (DM_Forest*) dm->data; 701 DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data; 702 DM base, adaptFrom; 703 DMForestTopology topoName; 704 PetscSF preCoarseToFine = NULL, coarseToPreFine = NULL; 705 PforestAdaptCtx ctx; 706 707 PetscFunctionBegin; 708 ctx.minLevel = PETSC_MAX_INT; 709 ctx.maxLevel = 0; 710 ctx.currLevel = 0; 711 ctx.anyChange = PETSC_FALSE; 712 /* sanity check */ 713 PetscCall(DMForestGetAdaptivityForest(dm,&adaptFrom)); 714 PetscCall(DMForestGetBaseDM(dm,&base)); 715 PetscCall(DMForestGetTopology(dm,&topoName)); 716 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"); 717 718 /* === Step 1: DMFTopology === */ 719 if (adaptFrom) { /* reference already created topology */ 720 PetscBool ispforest; 721 DM_Forest *aforest = (DM_Forest*) adaptFrom->data; 722 DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data; 723 724 PetscCall(PetscObjectTypeCompare((PetscObject)adaptFrom,DMPFOREST,&ispforest)); 725 PetscCheck(ispforest,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_NOTSAMETYPE,"Trying to adapt from %s, which is not %s",((PetscObject)adaptFrom)->type_name,DMPFOREST); 726 PetscCheck(apforest->topo,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONGSTATE,"The pre-adaptation forest must have a topology"); 727 PetscCall(DMSetUp(adaptFrom)); 728 PetscCall(DMForestGetBaseDM(dm,&base)); 729 PetscCall(DMForestGetTopology(dm,&topoName)); 730 } else if (base) { /* construct a connectivity from base */ 731 PetscBool isPlex, isDA; 732 733 PetscCall(PetscObjectGetName((PetscObject)base,&topoName)); 734 PetscCall(DMForestSetTopology(dm,topoName)); 735 PetscCall(PetscObjectTypeCompare((PetscObject)base,DMPLEX,&isPlex)); 736 PetscCall(PetscObjectTypeCompare((PetscObject)base,DMDA,&isDA)); 737 if (isPlex) { 738 MPI_Comm comm = PetscObjectComm((PetscObject)dm); 739 PetscInt depth; 740 PetscMPIInt size; 741 p4est_connectivity_t *conn = NULL; 742 DMFTopology_pforest *topo; 743 PetscInt *tree_face_to_uniq = NULL; 744 745 PetscCall(DMPlexGetDepth(base,&depth)); 746 if (depth == 1) { 747 DM connDM; 748 749 PetscCall(DMPlexInterpolate(base,&connDM)); 750 base = connDM; 751 PetscCall(DMForestSetBaseDM(dm,base)); 752 PetscCall(DMDestroy(&connDM)); 753 } 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); 754 PetscCallMPI(MPI_Comm_size(comm,&size)); 755 if (size > 1) { 756 DM dmRedundant; 757 PetscSF sf; 758 759 PetscCall(DMPlexGetRedundantDM(base,&sf,&dmRedundant)); 760 PetscCheck(dmRedundant,comm,PETSC_ERR_PLIB,"Could not create redundant DM"); 761 PetscCall(PetscObjectCompose((PetscObject)dmRedundant,"_base_migration_sf",(PetscObject)sf)); 762 PetscCall(PetscSFDestroy(&sf)); 763 base = dmRedundant; 764 PetscCall(DMForestSetBaseDM(dm,base)); 765 PetscCall(DMDestroy(&dmRedundant)); 766 } 767 PetscCall(DMViewFromOptions(base,NULL,"-dm_p4est_base_view")); 768 PetscCall(DMPlexCreateConnectivity_pforest(base,&conn,&tree_face_to_uniq)); 769 PetscCall(PetscNewLog(dm,&topo)); 770 topo->refct = 1; 771 topo->conn = conn; 772 topo->geom = NULL; 773 { 774 PetscErrorCode (*map)(DM,PetscInt,PetscInt,const PetscReal[],PetscReal[],void*); 775 void *mapCtx; 776 777 PetscCall(DMForestGetBaseCoordinateMapping(dm,&map,&mapCtx)); 778 if (map) { 779 DM_Forest_geometry_pforest *geom_pforest; 780 p4est_geometry_t *geom; 781 782 PetscCall(PetscNew(&geom_pforest)); 783 PetscCall(DMGetCoordinateDim(dm,&geom_pforest->coordDim)); 784 geom_pforest->map = map; 785 geom_pforest->mapCtx = mapCtx; 786 PetscStackCallP4estReturn(geom_pforest->inner,p4est_geometry_new_connectivity,(conn)); 787 PetscCall(PetscNew(&geom)); 788 geom->name = topoName; 789 geom->user = geom_pforest; 790 geom->X = GeometryMapping_pforest; 791 geom->destroy = GeometryDestroy_pforest; 792 topo->geom = geom; 793 } 794 } 795 topo->tree_face_to_uniq = tree_face_to_uniq; 796 pforest->topo = topo; 797 } else PetscCheck(!isDA,PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Not implemented yet"); 798 #if 0 799 PetscInt N[3], P[3]; 800 801 /* get the sizes, periodicities */ 802 /* ... */ 803 /* don't use Morton order */ 804 PetscCall(DMFTopologyCreateBrick_pforest(dm,N,P,&pforest->topo,PETSC_FALSE)); 805 #endif 806 { 807 PetscInt numLabels, l; 808 809 PetscCall(DMGetNumLabels(base,&numLabels)); 810 for (l = 0; l < numLabels; l++) { 811 PetscBool isDepth, isGhost, isVTK, isDim, isCellType; 812 DMLabel label, labelNew; 813 PetscInt defVal; 814 const char *name; 815 816 PetscCall(DMGetLabelName(base, l, &name)); 817 PetscCall(DMGetLabelByNum(base, l, &label)); 818 PetscCall(PetscStrcmp(name,"depth",&isDepth)); 819 if (isDepth) continue; 820 PetscCall(PetscStrcmp(name,"dim",&isDim)); 821 if (isDim) continue; 822 PetscCall(PetscStrcmp(name,"celltype",&isCellType)); 823 if (isCellType) continue; 824 PetscCall(PetscStrcmp(name,"ghost",&isGhost)); 825 if (isGhost) continue; 826 PetscCall(PetscStrcmp(name,"vtk",&isVTK)); 827 if (isVTK) continue; 828 PetscCall(DMCreateLabel(dm,name)); 829 PetscCall(DMGetLabel(dm,name,&labelNew)); 830 PetscCall(DMLabelGetDefaultValue(label,&defVal)); 831 PetscCall(DMLabelSetDefaultValue(labelNew,defVal)); 832 } 833 /* map dm points (internal plex) to base 834 we currently create the subpoint_map for the entire hierarchy, starting from the finest forest 835 and propagating back to the coarsest 836 This is not an optimal approach, since we need the map only on the coarsest level 837 during DMForestTransferVecFromBase */ 838 PetscCall(DMForestGetMinimumRefinement(dm,&l)); 839 if (!l) { 840 PetscCall(DMCreateLabel(dm,"_forest_base_subpoint_map")); 841 } 842 } 843 } else { /* construct from topology name */ 844 DMFTopology_pforest *topo; 845 846 PetscCall(DMFTopologyCreate_pforest(dm,topoName,&topo)); 847 pforest->topo = topo; 848 /* TODO: construct base? */ 849 } 850 851 /* === Step 2: get the leaves of the forest === */ 852 if (adaptFrom) { /* start with the old forest */ 853 DMLabel adaptLabel; 854 PetscInt defaultValue; 855 PetscInt numValues, numValuesGlobal, cLocalStart, count; 856 DM_Forest *aforest = (DM_Forest*) adaptFrom->data; 857 DM_Forest_pforest *apforest = (DM_Forest_pforest*) aforest->data; 858 PetscBool computeAdaptSF; 859 p4est_topidx_t flt, llt, t; 860 861 flt = apforest->forest->first_local_tree; 862 llt = apforest->forest->last_local_tree; 863 cLocalStart = apforest->cLocalStart; 864 PetscCall(DMForestGetComputeAdaptivitySF(dm,&computeAdaptSF)); 865 PetscStackCallP4estReturn(pforest->forest,p4est_copy,(apforest->forest, 0)); /* 0 indicates no data copying */ 866 PetscCall(DMForestGetAdaptivityLabel(dm,&adaptLabel)); 867 if (adaptLabel) { 868 /* apply the refinement/coarsening by flags, plus minimum/maximum refinement */ 869 PetscCall(DMLabelGetNumValues(adaptLabel,&numValues)); 870 PetscCallMPI(MPI_Allreduce(&numValues,&numValuesGlobal,1,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)adaptFrom))); 871 PetscCall(DMLabelGetDefaultValue(adaptLabel,&defaultValue)); 872 if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN_LAST) { /* uniform coarsen of the last level only (equivalent to DM_ADAPT_COARSEN for conforming grids) */ 873 PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel)); 874 PetscCall(DMPforestGetRefinementLevel(dm,&ctx.currLevel)); 875 pforest->forest->user_pointer = (void*) &ctx; 876 PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_currlevel,NULL)); 877 pforest->forest->user_pointer = (void*) dm; 878 PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL)); 879 /* we will have to change the offset after we compute the overlap */ 880 if (computeAdaptSF) { 881 PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL)); 882 } 883 } else if (!numValuesGlobal && defaultValue == DM_ADAPT_COARSEN) { /* uniform coarsen */ 884 PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel)); 885 pforest->forest->user_pointer = (void*) &ctx; 886 PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_uniform,NULL)); 887 pforest->forest->user_pointer = (void*) dm; 888 PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL)); 889 /* we will have to change the offset after we compute the overlap */ 890 if (computeAdaptSF) { 891 PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),pforest->forest,0,apforest->forest,apforest->cLocalStart,&coarseToPreFine,NULL)); 892 } 893 } else if (!numValuesGlobal && defaultValue == DM_ADAPT_REFINE) { /* uniform refine */ 894 PetscCall(DMForestGetMaximumRefinement(dm,&ctx.maxLevel)); 895 pforest->forest->user_pointer = (void*) &ctx; 896 PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_uniform,NULL)); 897 pforest->forest->user_pointer = (void*) dm; 898 PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL)); 899 /* we will have to change the offset after we compute the overlap */ 900 if (computeAdaptSF) { 901 PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,NULL)); 902 } 903 } else if (numValuesGlobal) { 904 p4est_t *p4est = pforest->forest; 905 PetscInt *cellFlags; 906 DMForestAdaptivityStrategy strategy; 907 PetscSF cellSF; 908 PetscInt c, cStart, cEnd; 909 PetscBool adaptAny; 910 911 PetscCall(DMForestGetMaximumRefinement(dm,&ctx.maxLevel)); 912 PetscCall(DMForestGetMinimumRefinement(dm,&ctx.minLevel)); 913 PetscCall(DMForestGetAdaptivityStrategy(dm,&strategy)); 914 PetscCall(PetscStrncmp(strategy,"any",3,&adaptAny)); 915 PetscCall(DMForestGetCellChart(adaptFrom,&cStart,&cEnd)); 916 PetscCall(DMForestGetCellSF(adaptFrom,&cellSF)); 917 PetscCall(PetscMalloc1(cEnd-cStart,&cellFlags)); 918 for (c = cStart; c < cEnd; c++) PetscCall(DMLabelGetValue(adaptLabel,c,&cellFlags[c-cStart])); 919 if (cellSF) { 920 if (adaptAny) { 921 PetscCall(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX)); 922 PetscCall(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MAX)); 923 } else { 924 PetscCall(PetscSFReduceBegin(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN)); 925 PetscCall(PetscSFReduceEnd(cellSF,MPIU_INT,cellFlags,cellFlags,MPI_MIN)); 926 } 927 } 928 for (t = flt, count = cLocalStart; t <= llt; t++) { 929 p4est_tree_t *tree = &(((p4est_tree_t*) p4est->trees->array)[t]); 930 PetscInt numQuads = (PetscInt) tree->quadrants.elem_count, i; 931 p4est_quadrant_t *quads = (p4est_quadrant_t *) tree->quadrants.array; 932 933 for (i = 0; i < numQuads; i++) { 934 p4est_quadrant_t *q = &quads[i]; 935 q->p.user_int = cellFlags[count++]; 936 } 937 } 938 PetscCall(PetscFree(cellFlags)); 939 940 pforest->forest->user_pointer = (void*) &ctx; 941 if (adaptAny) PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_any,pforest_init_determine)); 942 else PetscStackCallP4est(p4est_coarsen,(pforest->forest,0,pforest_coarsen_flag_all,pforest_init_determine)); 943 PetscStackCallP4est(p4est_refine,(pforest->forest,0,pforest_refine_flag,NULL)); 944 pforest->forest->user_pointer = (void*) dm; 945 PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL)); 946 if (computeAdaptSF) { 947 PetscCall(DMPforestComputeLocalCellTransferSF(PetscObjectComm((PetscObject)dm),apforest->forest,apforest->cLocalStart,pforest->forest,0,&preCoarseToFine,&coarseToPreFine)); 948 } 949 } 950 for (t = flt, count = cLocalStart; t <= llt; t++) { 951 p4est_tree_t *atree = &(((p4est_tree_t*) apforest->forest->trees->array)[t]); 952 p4est_tree_t *tree = &(((p4est_tree_t*) pforest->forest->trees->array)[t]); 953 PetscInt anumQuads = (PetscInt) atree->quadrants.elem_count, i; 954 PetscInt numQuads = (PetscInt) tree->quadrants.elem_count; 955 p4est_quadrant_t *aquads = (p4est_quadrant_t *) atree->quadrants.array; 956 p4est_quadrant_t *quads = (p4est_quadrant_t *) tree->quadrants.array; 957 958 if (anumQuads != numQuads) { 959 ctx.anyChange = PETSC_TRUE; 960 } else { 961 for (i = 0; i < numQuads; i++) { 962 p4est_quadrant_t *aq = &aquads[i]; 963 p4est_quadrant_t *q = &quads[i]; 964 965 if (aq->level != q->level) { 966 ctx.anyChange = PETSC_TRUE; 967 break; 968 } 969 } 970 } 971 if (ctx.anyChange) { 972 break; 973 } 974 } 975 } 976 { 977 PetscInt numLabels, l; 978 979 PetscCall(DMGetNumLabels(adaptFrom,&numLabels)); 980 for (l = 0; l < numLabels; l++) { 981 PetscBool isDepth, isCellType, isGhost, isVTK; 982 DMLabel label, labelNew; 983 PetscInt defVal; 984 const char *name; 985 986 PetscCall(DMGetLabelName(adaptFrom, l, &name)); 987 PetscCall(DMGetLabelByNum(adaptFrom, l, &label)); 988 PetscCall(PetscStrcmp(name,"depth",&isDepth)); 989 if (isDepth) continue; 990 PetscCall(PetscStrcmp(name,"celltype",&isCellType)); 991 if (isCellType) continue; 992 PetscCall(PetscStrcmp(name,"ghost",&isGhost)); 993 if (isGhost) continue; 994 PetscCall(PetscStrcmp(name,"vtk",&isVTK)); 995 if (isVTK) continue; 996 PetscCall(DMCreateLabel(dm,name)); 997 PetscCall(DMGetLabel(dm,name,&labelNew)); 998 PetscCall(DMLabelGetDefaultValue(label,&defVal)); 999 PetscCall(DMLabelSetDefaultValue(labelNew,defVal)); 1000 } 1001 } 1002 } else { /* initial */ 1003 PetscInt initLevel, minLevel; 1004 1005 PetscCall(DMForestGetInitialRefinement(dm,&initLevel)); 1006 PetscCall(DMForestGetMinimumRefinement(dm,&minLevel)); 1007 PetscStackCallP4estReturn(pforest->forest,p4est_new_ext,(PetscObjectComm((PetscObject)dm),pforest->topo->conn, 1008 0, /* minimum number of quadrants per processor */ 1009 initLevel, /* level of refinement */ 1010 1, /* uniform refinement */ 1011 0, /* we don't allocate any per quadrant data */ 1012 NULL, /* there is no special quadrant initialization */ 1013 (void*)dm)); /* this dm is the user context */ 1014 1015 if (initLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE; 1016 if (dm->setfromoptionscalled) { 1017 PetscBool flgPattern, flgFractal; 1018 PetscInt corner = 0; 1019 PetscInt corners[P4EST_CHILDREN], ncorner = P4EST_CHILDREN; 1020 PetscReal likelihood = 1./ P4EST_DIM; 1021 PetscInt pattern; 1022 const char *prefix; 1023 1024 PetscCall(PetscObjectGetOptionsPrefix((PetscObject)dm,&prefix)); 1025 PetscCall(PetscOptionsGetEList(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_pattern",DMRefinePatternName,PATTERN_COUNT,&pattern,&flgPattern)); 1026 PetscCall(PetscOptionsGetInt(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_corner",&corner,NULL)); 1027 PetscCall(PetscOptionsGetIntArray(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_fractal_corners",corners,&ncorner,&flgFractal)); 1028 PetscCall(PetscOptionsGetReal(((PetscObject)dm)->options,prefix,"-dm_p4est_refine_hash_likelihood",&likelihood,NULL)); 1029 1030 if (flgPattern) { 1031 DMRefinePatternCtx *ctx; 1032 PetscInt maxLevel; 1033 1034 PetscCall(DMForestGetMaximumRefinement(dm,&maxLevel)); 1035 PetscCall(PetscNewLog(dm,&ctx)); 1036 ctx->maxLevel = PetscMin(maxLevel,P4EST_QMAXLEVEL); 1037 if (initLevel + ctx->maxLevel > minLevel) pforest->coarsen_hierarchy = PETSC_TRUE; 1038 switch (pattern) { 1039 case PATTERN_HASH: 1040 ctx->refine_fn = DMRefinePattern_Hash; 1041 ctx->hashLikelihood = likelihood; 1042 break; 1043 case PATTERN_CORNER: 1044 ctx->corner = corner; 1045 ctx->refine_fn = DMRefinePattern_Corner; 1046 break; 1047 case PATTERN_CENTER: 1048 ctx->refine_fn = DMRefinePattern_Center; 1049 break; 1050 case PATTERN_FRACTAL: 1051 if (flgFractal) { 1052 PetscInt i; 1053 1054 for (i = 0; i < ncorner; i++) ctx->fractal[corners[i]] = PETSC_TRUE; 1055 } else { 1056 #if !defined(P4_TO_P8) 1057 ctx->fractal[0] = ctx->fractal[1] = ctx->fractal[2] = PETSC_TRUE; 1058 #else 1059 ctx->fractal[0] = ctx->fractal[3] = ctx->fractal[5] = ctx->fractal[6] = PETSC_TRUE; 1060 #endif 1061 } 1062 ctx->refine_fn = DMRefinePattern_Fractal; 1063 break; 1064 default: 1065 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_OUTOFRANGE,"Not a valid refinement pattern"); 1066 } 1067 1068 pforest->forest->user_pointer = (void*) ctx; 1069 PetscStackCallP4est(p4est_refine,(pforest->forest,1,ctx->refine_fn,NULL)); 1070 PetscStackCallP4est(p4est_balance,(pforest->forest,P4EST_CONNECT_FULL,NULL)); 1071 PetscCall(PetscFree(ctx)); 1072 pforest->forest->user_pointer = (void*) dm; 1073 } 1074 } 1075 } 1076 if (pforest->coarsen_hierarchy) { 1077 PetscInt initLevel, currLevel, minLevel; 1078 1079 PetscCall(DMPforestGetRefinementLevel(dm,&currLevel)); 1080 PetscCall(DMForestGetInitialRefinement(dm,&initLevel)); 1081 PetscCall(DMForestGetMinimumRefinement(dm,&minLevel)); 1082 if (currLevel > minLevel) { 1083 DM_Forest_pforest *coarse_pforest; 1084 DMLabel coarsen; 1085 DM coarseDM; 1086 1087 PetscCall(DMForestTemplate(dm,MPI_COMM_NULL,&coarseDM)); 1088 PetscCall(DMForestSetAdaptivityPurpose(coarseDM,DM_ADAPT_COARSEN)); 1089 PetscCall(DMLabelCreate(PETSC_COMM_SELF, "coarsen",&coarsen)); 1090 PetscCall(DMLabelSetDefaultValue(coarsen,DM_ADAPT_COARSEN)); 1091 PetscCall(DMForestSetAdaptivityLabel(coarseDM,coarsen)); 1092 PetscCall(DMLabelDestroy(&coarsen)); 1093 PetscCall(DMSetCoarseDM(dm,coarseDM)); 1094 PetscCall(PetscObjectDereference((PetscObject)coarseDM)); 1095 initLevel = currLevel == initLevel ? initLevel - 1 : initLevel; 1096 PetscCall(DMForestSetInitialRefinement(coarseDM,initLevel)); 1097 PetscCall(DMForestSetMinimumRefinement(coarseDM,minLevel)); 1098 coarse_pforest = (DM_Forest_pforest*) ((DM_Forest*) coarseDM->data)->data; 1099 coarse_pforest->coarsen_hierarchy = PETSC_TRUE; 1100 } 1101 } 1102 1103 { /* repartitioning and overlap */ 1104 PetscMPIInt size, rank; 1105 1106 PetscCallMPI(MPI_Comm_size(PetscObjectComm((PetscObject)dm),&size)); 1107 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank)); 1108 if ((size > 1) && (pforest->partition_for_coarsening || forest->cellWeights || forest->weightCapacity != 1. || forest->weightsFactor != 1.)) { 1109 PetscBool copyForest = PETSC_FALSE; 1110 p4est_t *forest_copy = NULL; 1111 p4est_gloidx_t shipped = 0; 1112 1113 if (preCoarseToFine || coarseToPreFine) copyForest = PETSC_TRUE; 1114 if (copyForest) PetscStackCallP4estReturn(forest_copy,p4est_copy,(pforest->forest,0)); 1115 1116 if (!forest->cellWeights && forest->weightCapacity == 1. && forest->weightsFactor == 1.) { 1117 PetscStackCallP4estReturn(shipped,p4est_partition_ext,(pforest->forest,(int)pforest->partition_for_coarsening,NULL)); 1118 } else SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_PLIB,"Non-uniform partition cases not implemented yet"); 1119 if (shipped) ctx.anyChange = PETSC_TRUE; 1120 if (forest_copy) { 1121 if (preCoarseToFine || coarseToPreFine) { 1122 PetscSF repartSF; /* repartSF has roots in the old partition */ 1123 PetscInt pStart = -1, pEnd = -1, p; 1124 PetscInt numRoots, numLeaves; 1125 PetscSFNode *repartRoots; 1126 p4est_gloidx_t postStart = pforest->forest->global_first_quadrant[rank]; 1127 p4est_gloidx_t postEnd = pforest->forest->global_first_quadrant[rank+1]; 1128 p4est_gloidx_t partOffset = postStart; 1129 1130 numRoots = (PetscInt) (forest_copy->global_first_quadrant[rank + 1] - forest_copy->global_first_quadrant[rank]); 1131 numLeaves = (PetscInt) (postEnd - postStart); 1132 PetscCall(DMPforestComputeOverlappingRanks(size,rank,pforest->forest,forest_copy,&pStart,&pEnd)); 1133 PetscCall(PetscMalloc1((PetscInt) pforest->forest->local_num_quadrants,&repartRoots)); 1134 for (p = pStart; p < pEnd; p++) { 1135 p4est_gloidx_t preStart = forest_copy->global_first_quadrant[p]; 1136 p4est_gloidx_t preEnd = forest_copy->global_first_quadrant[p+1]; 1137 PetscInt q; 1138 1139 if (preEnd == preStart) continue; 1140 PetscCheck(preStart <= postStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Bad partition overlap computation"); 1141 preEnd = preEnd > postEnd ? postEnd : preEnd; 1142 for (q = partOffset; q < preEnd; q++) { 1143 repartRoots[q - postStart].rank = p; 1144 repartRoots[q - postStart].index = partOffset - preStart; 1145 } 1146 partOffset = preEnd; 1147 } 1148 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&repartSF)); 1149 PetscCall(PetscSFSetGraph(repartSF,numRoots,numLeaves,NULL,PETSC_OWN_POINTER,repartRoots,PETSC_OWN_POINTER)); 1150 PetscCall(PetscSFSetUp(repartSF)); 1151 if (preCoarseToFine) { 1152 PetscSF repartSFembed, preCoarseToFineNew; 1153 PetscInt nleaves; 1154 const PetscInt *leaves; 1155 1156 PetscCall(PetscSFSetUp(preCoarseToFine)); 1157 PetscCall(PetscSFGetGraph(preCoarseToFine,NULL,&nleaves,&leaves,NULL)); 1158 if (leaves) { 1159 PetscCall(PetscSFCreateEmbeddedRootSF(repartSF,nleaves,leaves,&repartSFembed)); 1160 } else { 1161 repartSFembed = repartSF; 1162 PetscCall(PetscObjectReference((PetscObject)repartSFembed)); 1163 } 1164 PetscCall(PetscSFCompose(preCoarseToFine,repartSFembed,&preCoarseToFineNew)); 1165 PetscCall(PetscSFDestroy(&preCoarseToFine)); 1166 PetscCall(PetscSFDestroy(&repartSFembed)); 1167 preCoarseToFine = preCoarseToFineNew; 1168 } 1169 if (coarseToPreFine) { 1170 PetscSF repartSFinv, coarseToPreFineNew; 1171 1172 PetscCall(PetscSFCreateInverseSF(repartSF,&repartSFinv)); 1173 PetscCall(PetscSFCompose(repartSFinv,coarseToPreFine,&coarseToPreFineNew)); 1174 PetscCall(PetscSFDestroy(&coarseToPreFine)); 1175 PetscCall(PetscSFDestroy(&repartSFinv)); 1176 coarseToPreFine = coarseToPreFineNew; 1177 } 1178 PetscCall(PetscSFDestroy(&repartSF)); 1179 } 1180 PetscStackCallP4est(p4est_destroy,(forest_copy)); 1181 } 1182 } 1183 if (size > 1) { 1184 PetscInt overlap; 1185 1186 PetscCall(DMForestGetPartitionOverlap(dm,&overlap)); 1187 1188 if (adaptFrom) { 1189 PetscInt aoverlap; 1190 1191 PetscCall(DMForestGetPartitionOverlap(adaptFrom,&aoverlap)); 1192 if (aoverlap != overlap) { 1193 ctx.anyChange = PETSC_TRUE; 1194 } 1195 } 1196 1197 if (overlap > 0) { 1198 PetscInt i, cLocalStart; 1199 PetscInt cEnd; 1200 PetscSF preCellSF = NULL, cellSF = NULL; 1201 1202 PetscStackCallP4estReturn(pforest->ghost,p4est_ghost_new,(pforest->forest,P4EST_CONNECT_FULL)); 1203 PetscStackCallP4estReturn(pforest->lnodes,p4est_lnodes_new,(pforest->forest,pforest->ghost,-P4EST_DIM)); 1204 PetscStackCallP4est(p4est_ghost_support_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost)); 1205 for (i = 1; i < overlap; i++) PetscStackCallP4est(p4est_ghost_expand_by_lnodes,(pforest->forest,pforest->lnodes,pforest->ghost)); 1206 1207 cLocalStart = pforest->cLocalStart = pforest->ghost->proc_offsets[rank]; 1208 cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[size]; 1209 1210 /* shift sfs by cLocalStart, expand by cell SFs */ 1211 if (preCoarseToFine || coarseToPreFine) { 1212 if (adaptFrom) PetscCall(DMForestGetCellSF(adaptFrom,&preCellSF)); 1213 dm->setupcalled = PETSC_TRUE; 1214 PetscCall(DMForestGetCellSF(dm,&cellSF)); 1215 } 1216 if (preCoarseToFine) { 1217 PetscSF preCoarseToFineNew; 1218 PetscInt nleaves, nroots, *leavesNew, i, nleavesNew; 1219 const PetscInt *leaves; 1220 const PetscSFNode *remotes; 1221 PetscSFNode *remotesAll; 1222 1223 PetscCall(PetscSFSetUp(preCoarseToFine)); 1224 PetscCall(PetscSFGetGraph(preCoarseToFine,&nroots,&nleaves,&leaves,&remotes)); 1225 PetscCall(PetscMalloc1(cEnd,&remotesAll)); 1226 for (i = 0; i < cEnd; i++) { 1227 remotesAll[i].rank = -1; 1228 remotesAll[i].index = -1; 1229 } 1230 for (i = 0; i < nleaves; i++) remotesAll[(leaves ? leaves[i] : i) + cLocalStart] = remotes[i]; 1231 PetscCall(PetscSFSetUp(cellSF)); 1232 PetscCall(PetscSFBcastBegin(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE)); 1233 PetscCall(PetscSFBcastEnd(cellSF,MPIU_2INT,remotesAll,remotesAll,MPI_REPLACE)); 1234 nleavesNew = 0; 1235 for (i = 0; i < nleaves; i++) { 1236 if (remotesAll[i].rank >= 0) nleavesNew++; 1237 } 1238 PetscCall(PetscMalloc1(nleavesNew,&leavesNew)); 1239 nleavesNew = 0; 1240 for (i = 0; i < nleaves; i++) { 1241 if (remotesAll[i].rank >= 0) { 1242 leavesNew[nleavesNew] = i; 1243 if (i > nleavesNew) remotesAll[nleavesNew] = remotesAll[i]; 1244 nleavesNew++; 1245 } 1246 } 1247 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&preCoarseToFineNew)); 1248 if (nleavesNew < cEnd) { 1249 PetscCall(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,leavesNew,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES)); 1250 } else { /* all cells are leaves */ 1251 PetscCall(PetscFree(leavesNew)); 1252 PetscCall(PetscSFSetGraph(preCoarseToFineNew,nroots,nleavesNew,NULL,PETSC_OWN_POINTER,remotesAll,PETSC_COPY_VALUES)); 1253 } 1254 PetscCall(PetscFree(remotesAll)); 1255 PetscCall(PetscSFDestroy(&preCoarseToFine)); 1256 preCoarseToFine = preCoarseToFineNew; 1257 preCoarseToFine = preCoarseToFineNew; 1258 } 1259 if (coarseToPreFine) { 1260 PetscSF coarseToPreFineNew; 1261 PetscInt nleaves, nroots, i, nleavesCellSF, nleavesExpanded, *leavesNew; 1262 const PetscInt *leaves; 1263 const PetscSFNode *remotes; 1264 PetscSFNode *remotesNew, *remotesNewRoot, *remotesExpanded; 1265 1266 PetscCall(PetscSFSetUp(coarseToPreFine)); 1267 PetscCall(PetscSFGetGraph(coarseToPreFine,&nroots,&nleaves,&leaves,&remotes)); 1268 PetscCall(PetscSFGetGraph(preCellSF,NULL,&nleavesCellSF,NULL,NULL)); 1269 PetscCall(PetscMalloc1(nroots,&remotesNewRoot)); 1270 PetscCall(PetscMalloc1(nleaves,&remotesNew)); 1271 for (i = 0; i < nroots; i++) { 1272 remotesNewRoot[i].rank = rank; 1273 remotesNewRoot[i].index = i + cLocalStart; 1274 } 1275 PetscCall(PetscSFBcastBegin(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE)); 1276 PetscCall(PetscSFBcastEnd(coarseToPreFine,MPIU_2INT,remotesNewRoot,remotesNew,MPI_REPLACE)); 1277 PetscCall(PetscFree(remotesNewRoot)); 1278 PetscCall(PetscMalloc1(nleavesCellSF,&remotesExpanded)); 1279 for (i = 0; i < nleavesCellSF; i++) { 1280 remotesExpanded[i].rank = -1; 1281 remotesExpanded[i].index = -1; 1282 } 1283 for (i = 0; i < nleaves; i++) remotesExpanded[leaves ? leaves[i] : i] = remotesNew[i]; 1284 PetscCall(PetscFree(remotesNew)); 1285 PetscCall(PetscSFBcastBegin(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE)); 1286 PetscCall(PetscSFBcastEnd(preCellSF,MPIU_2INT,remotesExpanded,remotesExpanded,MPI_REPLACE)); 1287 1288 nleavesExpanded = 0; 1289 for (i = 0; i < nleavesCellSF; i++) { 1290 if (remotesExpanded[i].rank >= 0) nleavesExpanded++; 1291 } 1292 PetscCall(PetscMalloc1(nleavesExpanded,&leavesNew)); 1293 nleavesExpanded = 0; 1294 for (i = 0; i < nleavesCellSF; i++) { 1295 if (remotesExpanded[i].rank >= 0) { 1296 leavesNew[nleavesExpanded] = i; 1297 if (i > nleavesExpanded) remotesExpanded[nleavesExpanded] = remotes[i]; 1298 nleavesExpanded++; 1299 } 1300 } 1301 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&coarseToPreFineNew)); 1302 if (nleavesExpanded < nleavesCellSF) { 1303 PetscCall(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,leavesNew,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES)); 1304 } else { 1305 PetscCall(PetscFree(leavesNew)); 1306 PetscCall(PetscSFSetGraph(coarseToPreFineNew,cEnd,nleavesExpanded,NULL,PETSC_OWN_POINTER,remotesExpanded,PETSC_COPY_VALUES)); 1307 } 1308 PetscCall(PetscFree(remotesExpanded)); 1309 PetscCall(PetscSFDestroy(&coarseToPreFine)); 1310 coarseToPreFine = coarseToPreFineNew; 1311 } 1312 } 1313 } 1314 } 1315 forest->preCoarseToFine = preCoarseToFine; 1316 forest->coarseToPreFine = coarseToPreFine; 1317 dm->setupcalled = PETSC_TRUE; 1318 PetscCallMPI(MPI_Allreduce(&ctx.anyChange,&(pforest->adaptivitySuccess),1,MPIU_BOOL,MPI_LOR,PetscObjectComm((PetscObject)dm))); 1319 PetscCall(DMPforestGetPlex(dm,NULL)); 1320 PetscFunctionReturn(0); 1321 } 1322 1323 #define DMForestGetAdaptivitySuccess_pforest _append_pforest(DMForestGetAdaptivitySuccess) 1324 static PetscErrorCode DMForestGetAdaptivitySuccess_pforest(DM dm, PetscBool *success) 1325 { 1326 DM_Forest *forest; 1327 DM_Forest_pforest *pforest; 1328 1329 PetscFunctionBegin; 1330 forest = (DM_Forest *) dm->data; 1331 pforest = (DM_Forest_pforest *) forest->data; 1332 *success = pforest->adaptivitySuccess; 1333 PetscFunctionReturn(0); 1334 } 1335 1336 #define DMView_ASCII_pforest _append_pforest(DMView_ASCII) 1337 static PetscErrorCode DMView_ASCII_pforest(PetscObject odm, PetscViewer viewer) 1338 { 1339 DM dm = (DM) odm; 1340 1341 PetscFunctionBegin; 1342 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1343 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1344 PetscCall(DMSetUp(dm)); 1345 switch (viewer->format) { 1346 case PETSC_VIEWER_DEFAULT: 1347 case PETSC_VIEWER_ASCII_INFO: 1348 { 1349 PetscInt dim; 1350 const char *name; 1351 1352 PetscCall(PetscObjectGetName((PetscObject) dm, &name)); 1353 PetscCall(DMGetDimension(dm, &dim)); 1354 if (name) PetscCall(PetscViewerASCIIPrintf(viewer, "Forest %s in %" PetscInt_FMT " dimensions:\n", name, dim)); 1355 else PetscCall(PetscViewerASCIIPrintf(viewer, "Forest in %" PetscInt_FMT " dimensions:\n", dim)); 1356 } 1357 case PETSC_VIEWER_ASCII_INFO_DETAIL: 1358 case PETSC_VIEWER_LOAD_BALANCE: 1359 { 1360 DM plex; 1361 1362 PetscCall(DMPforestGetPlex(dm, &plex)); 1363 PetscCall(DMView(plex, viewer)); 1364 } 1365 break; 1366 default: SETERRQ(PetscObjectComm((PetscObject) dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]); 1367 } 1368 PetscFunctionReturn(0); 1369 } 1370 1371 #define DMView_VTK_pforest _append_pforest(DMView_VTK) 1372 static PetscErrorCode DMView_VTK_pforest(PetscObject odm, PetscViewer viewer) 1373 { 1374 DM dm = (DM) odm; 1375 DM_Forest *forest = (DM_Forest*) dm->data; 1376 DM_Forest_pforest *pforest = (DM_Forest_pforest*) forest->data; 1377 PetscBool isvtk; 1378 PetscReal vtkScale = 1. - PETSC_MACHINE_EPSILON; 1379 PetscViewer_VTK *vtk = (PetscViewer_VTK*)viewer->data; 1380 const char *name; 1381 char *filenameStrip = NULL; 1382 PetscBool hasExt; 1383 size_t len; 1384 p4est_geometry_t *geom; 1385 1386 PetscFunctionBegin; 1387 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1388 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1389 PetscCall(DMSetUp(dm)); 1390 geom = pforest->topo->geom; 1391 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1392 PetscCheck(isvtk,PetscObjectComm((PetscObject)viewer), PETSC_ERR_ARG_INCOMP, "Cannot use viewer type %s", ((PetscObject)viewer)->type_name); 1393 switch (viewer->format) { 1394 case PETSC_VIEWER_VTK_VTU: 1395 PetscCheck(pforest->forest,PetscObjectComm(odm),PETSC_ERR_ARG_WRONG,"DM has not been setup with a valid forest"); 1396 name = vtk->filename; 1397 PetscCall(PetscStrlen(name,&len)); 1398 PetscCall(PetscStrcasecmp(name+len-4,".vtu",&hasExt)); 1399 if (hasExt) { 1400 PetscCall(PetscStrallocpy(name,&filenameStrip)); 1401 filenameStrip[len-4]='\0'; 1402 name = filenameStrip; 1403 } 1404 if (!pforest->topo->geom) PetscStackCallP4estReturn(geom,p4est_geometry_new_connectivity,(pforest->topo->conn)); 1405 { 1406 p4est_vtk_context_t *pvtk; 1407 int footerr; 1408 1409 PetscStackCallP4estReturn(pvtk,p4est_vtk_context_new,(pforest->forest,name)); 1410 PetscStackCallP4est(p4est_vtk_context_set_geom,(pvtk,geom)); 1411 PetscStackCallP4est(p4est_vtk_context_set_scale,(pvtk,(double)vtkScale)); 1412 PetscStackCallP4estReturn(pvtk,p4est_vtk_write_header,(pvtk)); 1413 PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_header() failed"); 1414 PetscStackCallP4estReturn(pvtk,p4est_vtk_write_cell_dataf,(pvtk, 1415 1, /* write tree */ 1416 1, /* write level */ 1417 1, /* write rank */ 1418 0, /* do not wrap rank */ 1419 0, /* no scalar fields */ 1420 0, /* no vector fields */ 1421 pvtk)); 1422 PetscCheck(pvtk,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_cell_dataf() failed"); 1423 PetscStackCallP4estReturn(footerr,p4est_vtk_write_footer,(pvtk)); 1424 PetscCheck(!footerr,PetscObjectComm((PetscObject)odm),PETSC_ERR_LIB,P4EST_STRING "_vtk_write_footer() failed"); 1425 } 1426 if (!pforest->topo->geom) PetscStackCallP4est(p4est_geometry_destroy,(geom)); 1427 PetscCall(PetscFree(filenameStrip)); 1428 break; 1429 default: SETERRQ(PetscObjectComm((PetscObject)dm), PETSC_ERR_SUP, "No support for format '%s'", PetscViewerFormats[viewer->format]); 1430 } 1431 PetscFunctionReturn(0); 1432 } 1433 1434 #define DMView_HDF5_pforest _append_pforest(DMView_HDF5) 1435 static PetscErrorCode DMView_HDF5_pforest(DM dm, PetscViewer viewer) 1436 { 1437 DM plex; 1438 1439 PetscFunctionBegin; 1440 PetscCall(DMSetUp(dm)); 1441 PetscCall(DMPforestGetPlex(dm, &plex)); 1442 PetscCall(DMView(plex, viewer)); 1443 PetscFunctionReturn(0); 1444 } 1445 1446 #define DMView_GLVis_pforest _append_pforest(DMView_GLVis) 1447 static PetscErrorCode DMView_GLVis_pforest(DM dm, PetscViewer viewer) 1448 { 1449 DM plex; 1450 1451 PetscFunctionBegin; 1452 PetscCall(DMSetUp(dm)); 1453 PetscCall(DMPforestGetPlex(dm, &plex)); 1454 PetscCall(DMView(plex, viewer)); 1455 PetscFunctionReturn(0); 1456 } 1457 1458 #define DMView_pforest _append_pforest(DMView) 1459 static PetscErrorCode DMView_pforest(DM dm, PetscViewer viewer) 1460 { 1461 PetscBool isascii, isvtk, ishdf5, isglvis; 1462 1463 PetscFunctionBegin; 1464 PetscValidHeaderSpecific(dm, DM_CLASSID, 1); 1465 PetscValidHeaderSpecific(viewer, PETSC_VIEWER_CLASSID, 2); 1466 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERASCII, &isascii)); 1467 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERVTK, &isvtk)); 1468 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERHDF5, &ishdf5)); 1469 PetscCall(PetscObjectTypeCompare((PetscObject) viewer, PETSCVIEWERGLVIS, &isglvis)); 1470 if (isascii) { 1471 PetscCall(DMView_ASCII_pforest((PetscObject) dm,viewer)); 1472 } else if (isvtk) { 1473 PetscCall(DMView_VTK_pforest((PetscObject) dm,viewer)); 1474 } else if (ishdf5) { 1475 PetscCall(DMView_HDF5_pforest(dm, viewer)); 1476 } else if (isglvis) { 1477 PetscCall(DMView_GLVis_pforest(dm, viewer)); 1478 } else SETERRQ(PetscObjectComm((PetscObject) dm),PETSC_ERR_SUP,"Viewer not supported (not VTK, HDF5, or GLVis)"); 1479 PetscFunctionReturn(0); 1480 } 1481 1482 static PetscErrorCode PforestConnectivityEnumerateFacets(p4est_connectivity_t *conn, PetscInt **tree_face_to_uniq) 1483 { 1484 PetscInt *ttf, f, t, g, count; 1485 PetscInt numFacets; 1486 1487 PetscFunctionBegin; 1488 numFacets = conn->num_trees * P4EST_FACES; 1489 PetscCall(PetscMalloc1(numFacets,&ttf)); 1490 for (f = 0; f < numFacets; f++) ttf[f] = -1; 1491 for (g = 0, count = 0, t = 0; t < conn->num_trees; t++) { 1492 for (f = 0; f < P4EST_FACES; f++, g++) { 1493 if (ttf[g] == -1) { 1494 PetscInt ng; 1495 1496 ttf[g] = count++; 1497 ng = conn->tree_to_tree[g] * P4EST_FACES + (conn->tree_to_face[g] % P4EST_FACES); 1498 ttf[ng] = ttf[g]; 1499 } 1500 } 1501 } 1502 *tree_face_to_uniq = ttf; 1503 PetscFunctionReturn(0); 1504 } 1505 1506 static PetscErrorCode DMPlexCreateConnectivity_pforest(DM dm, p4est_connectivity_t **connOut, PetscInt **tree_face_to_uniq) 1507 { 1508 p4est_topidx_t numTrees, numVerts, numCorns, numCtt; 1509 PetscSection ctt; 1510 #if defined(P4_TO_P8) 1511 p4est_topidx_t numEdges, numEtt; 1512 PetscSection ett; 1513 PetscInt eStart, eEnd, e, ettSize; 1514 PetscInt vertOff = 1 + P4EST_FACES + P8EST_EDGES; 1515 PetscInt edgeOff = 1 + P4EST_FACES; 1516 #else 1517 PetscInt vertOff = 1 + P4EST_FACES; 1518 #endif 1519 p4est_connectivity_t *conn; 1520 PetscInt cStart, cEnd, c, vStart, vEnd, v, fStart, fEnd, f; 1521 PetscInt *star = NULL, *closure = NULL, closureSize, starSize, cttSize; 1522 PetscInt *ttf; 1523 1524 PetscFunctionBegin; 1525 /* 1: count objects, allocate */ 1526 PetscCall(DMPlexGetSimplexOrBoxCells(dm,0,&cStart,&cEnd)); 1527 PetscCall(P4estTopidxCast(cEnd-cStart,&numTrees)); 1528 numVerts = P4EST_CHILDREN * numTrees; 1529 PetscCall(DMPlexGetDepthStratum(dm,0,&vStart,&vEnd)); 1530 PetscCall(P4estTopidxCast(vEnd-vStart,&numCorns)); 1531 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&ctt)); 1532 PetscCall(PetscSectionSetChart(ctt,vStart,vEnd)); 1533 for (v = vStart; v < vEnd; v++) { 1534 PetscInt s; 1535 1536 PetscCall(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star)); 1537 for (s = 0; s < starSize; s++) { 1538 PetscInt p = star[2*s]; 1539 1540 if (p >= cStart && p < cEnd) { 1541 /* we want to count every time cell p references v, so we see how many times it comes up in the closure. This 1542 * only protects against periodicity problems */ 1543 PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure)); 1544 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); 1545 for (c = 0; c < P4EST_CHILDREN; c++) { 1546 PetscInt cellVert = closure[2 * (c + vertOff)]; 1547 1548 PetscCheck(cellVert >= vStart && cellVert < vEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: vertices"); 1549 if (cellVert == v) { 1550 PetscCall(PetscSectionAddDof(ctt,v,1)); 1551 } 1552 } 1553 PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure)); 1554 } 1555 } 1556 PetscCall(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star)); 1557 } 1558 PetscCall(PetscSectionSetUp(ctt)); 1559 PetscCall(PetscSectionGetStorageSize(ctt,&cttSize)); 1560 PetscCall(P4estTopidxCast(cttSize,&numCtt)); 1561 #if defined(P4_TO_P8) 1562 PetscCall(DMPlexGetSimplexOrBoxCells(dm,P4EST_DIM-1,&eStart,&eEnd)); 1563 PetscCall(P4estTopidxCast(eEnd-eStart,&numEdges)); 1564 PetscCall(PetscSectionCreate(PETSC_COMM_SELF,&ett)); 1565 PetscCall(PetscSectionSetChart(ett,eStart,eEnd)); 1566 for (e = eStart; e < eEnd; e++) { 1567 PetscInt s; 1568 1569 PetscCall(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star)); 1570 for (s = 0; s < starSize; s++) { 1571 PetscInt p = star[2*s]; 1572 1573 if (p >= cStart && p < cEnd) { 1574 /* we want to count every time cell p references e, so we see how many times it comes up in the closure. This 1575 * only protects against periodicity problems */ 1576 PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure)); 1577 PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_ARG_INCOMP,"Cell with wrong closure size"); 1578 for (c = 0; c < P8EST_EDGES; c++) { 1579 PetscInt cellEdge = closure[2 * (c + edgeOff)]; 1580 1581 PetscCheck(cellEdge >= eStart && cellEdge < eEnd,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure: edges"); 1582 if (cellEdge == e) { 1583 PetscCall(PetscSectionAddDof(ett,e,1)); 1584 } 1585 } 1586 PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure)); 1587 } 1588 } 1589 PetscCall(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star)); 1590 } 1591 PetscCall(PetscSectionSetUp(ett)); 1592 PetscCall(PetscSectionGetStorageSize(ett,&ettSize)); 1593 PetscCall(P4estTopidxCast(ettSize,&numEtt)); 1594 1595 /* This routine allocates space for the arrays, which we fill below */ 1596 PetscStackCallP4estReturn(conn,p8est_connectivity_new,(numVerts,numTrees,numEdges,numEtt,numCorns,numCtt)); 1597 #else 1598 PetscStackCallP4estReturn(conn,p4est_connectivity_new,(numVerts,numTrees,numCorns,numCtt)); 1599 #endif 1600 1601 /* 2: visit every face, determine neighboring cells(trees) */ 1602 PetscCall(DMPlexGetSimplexOrBoxCells(dm,1,&fStart,&fEnd)); 1603 PetscCall(PetscMalloc1((cEnd-cStart) * P4EST_FACES,&ttf)); 1604 for (f = fStart; f < fEnd; f++) { 1605 PetscInt numSupp, s; 1606 PetscInt myFace[2] = {-1, -1}; 1607 PetscInt myOrnt[2] = {PETSC_MIN_INT, PETSC_MIN_INT}; 1608 const PetscInt *supp; 1609 1610 PetscCall(DMPlexGetSupportSize(dm, f, &numSupp)); 1611 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); 1612 PetscCall(DMPlexGetSupport(dm, f, &supp)); 1613 1614 for (s = 0; s < numSupp; s++) { 1615 PetscInt p = supp[s]; 1616 1617 if (p >= cEnd) { 1618 numSupp--; 1619 if (s) supp = &supp[1 - s]; 1620 break; 1621 } 1622 } 1623 for (s = 0; s < numSupp; s++) { 1624 PetscInt p = supp[s], i; 1625 PetscInt numCone; 1626 DMPolytopeType ct; 1627 const PetscInt *cone; 1628 const PetscInt *ornt; 1629 PetscInt orient = PETSC_MIN_INT; 1630 1631 PetscCall(DMPlexGetConeSize(dm, p, &numCone)); 1632 PetscCheck(numCone == P4EST_FACES,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %" PetscInt_FMT " has %" PetscInt_FMT " facets, expect %d",p,numCone,P4EST_FACES); 1633 PetscCall(DMPlexGetCone(dm, p, &cone)); 1634 PetscCall(DMPlexGetCellType(dm, cone[0], &ct)); 1635 PetscCall(DMPlexGetConeOrientation(dm, p, &ornt)); 1636 for (i = 0; i < P4EST_FACES; i++) { 1637 if (cone[i] == f) { 1638 orient = DMPolytopeConvertNewOrientation_Internal(ct, ornt[i]); 1639 break; 1640 } 1641 } 1642 PetscCheck(i < P4EST_FACES,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %" PetscInt_FMT " faced %" PetscInt_FMT " mismatch",p,f); 1643 if (p < cStart || p >= cEnd) { 1644 DMPolytopeType ct; 1645 PetscCall(DMPlexGetCellType(dm, p, &ct)); 1646 SETERRQ(PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"cell %" PetscInt_FMT " (%s) should be in [%" PetscInt_FMT ", %" PetscInt_FMT ")",p,DMPolytopeTypes[ct],cStart,cEnd); 1647 } 1648 ttf[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = f - fStart; 1649 if (numSupp == 1) { 1650 /* boundary faces indicated by self reference */ 1651 conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = p - cStart; 1652 conn->tree_to_face[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = (int8_t) PetscFaceToP4estFace[i]; 1653 } else { 1654 const PetscInt N = P4EST_CHILDREN / 2; 1655 1656 conn->tree_to_tree[P4EST_FACES * (p - cStart) + PetscFaceToP4estFace[i]] = supp[1 - s] - cStart; 1657 myFace[s] = PetscFaceToP4estFace[i]; 1658 /* get the orientation of cell p in p4est-type closure to facet f, by composing the p4est-closure to 1659 * petsc-closure permutation and the petsc-closure to facet orientation */ 1660 myOrnt[s] = DihedralCompose(N,orient,DMPolytopeConvertNewOrientation_Internal(ct, P4estFaceToPetscOrnt[myFace[s]])); 1661 } 1662 } 1663 if (numSupp == 2) { 1664 for (s = 0; s < numSupp; s++) { 1665 PetscInt p = supp[s]; 1666 PetscInt orntAtoB; 1667 PetscInt p4estOrient; 1668 const PetscInt N = P4EST_CHILDREN / 2; 1669 1670 /* composing the forward permutation with the other cell's inverse permutation gives the self-to-neighbor 1671 * permutation of this cell-facet's cone */ 1672 orntAtoB = DihedralCompose(N,DihedralInvert(N,myOrnt[1-s]),myOrnt[s]); 1673 1674 /* convert cone-description permutation (i.e., edges around facet) to cap-description permutation (i.e., 1675 * vertices around facet) */ 1676 #if !defined(P4_TO_P8) 1677 p4estOrient = orntAtoB < 0 ? -(orntAtoB + 1) : orntAtoB; 1678 #else 1679 { 1680 PetscInt firstVert = orntAtoB < 0 ? ((-orntAtoB) % N) : orntAtoB; 1681 PetscInt p4estFirstVert = firstVert < 2 ? firstVert : (firstVert ^ 1); 1682 1683 /* swap bits */ 1684 p4estOrient = ((myFace[s] <= myFace[1 - s]) || (orntAtoB < 0)) ? p4estFirstVert : ((p4estFirstVert >> 1) | ((p4estFirstVert & 1) << 1)); 1685 } 1686 #endif 1687 /* encode neighbor face and orientation in tree_to_face per p4est_connectivity standard (see 1688 * p4est_connectivity.h, p8est_connectivity.h) */ 1689 conn->tree_to_face[P4EST_FACES * (p - cStart) + myFace[s]] = (int8_t) myFace[1 - s] + p4estOrient * P4EST_FACES; 1690 } 1691 } 1692 } 1693 1694 #if defined(P4_TO_P8) 1695 /* 3: visit every edge */ 1696 conn->ett_offset[0] = 0; 1697 for (e = eStart; e < eEnd; e++) { 1698 PetscInt off, s; 1699 1700 PetscCall(PetscSectionGetOffset(ett,e,&off)); 1701 conn->ett_offset[e - eStart] = (p4est_topidx_t) off; 1702 PetscCall(DMPlexGetTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star)); 1703 for (s = 0; s < starSize; s++) { 1704 PetscInt p = star[2 * s]; 1705 1706 if (p >= cStart && p < cEnd) { 1707 PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure)); 1708 PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure"); 1709 for (c = 0; c < P8EST_EDGES; c++) { 1710 PetscInt cellEdge = closure[2 * (c + edgeOff)]; 1711 PetscInt cellOrnt = closure[2 * (c + edgeOff) + 1]; 1712 DMPolytopeType ct; 1713 1714 PetscCall(DMPlexGetCellType(dm, cellEdge, &ct)); 1715 cellOrnt = DMPolytopeConvertNewOrientation_Internal(ct, cellOrnt); 1716 if (cellEdge == e) { 1717 PetscInt p4estEdge = PetscEdgeToP4estEdge[c]; 1718 PetscInt totalOrient; 1719 1720 /* compose p4est-closure to petsc-closure permutation and petsc-closure to edge orientation */ 1721 totalOrient = DihedralCompose(2,cellOrnt,DMPolytopeConvertNewOrientation_Internal(DM_POLYTOPE_SEGMENT, P4estEdgeToPetscOrnt[p4estEdge])); 1722 /* p4est orientations are positive: -2 => 1, -1 => 0 */ 1723 totalOrient = (totalOrient < 0) ? -(totalOrient + 1) : totalOrient; 1724 conn->edge_to_tree[off] = (p4est_locidx_t) (p - cStart); 1725 /* encode cell-edge and orientation in edge_to_edge per p8est_connectivity standart (see 1726 * p8est_connectivity.h) */ 1727 conn->edge_to_edge[off++] = (int8_t) p4estEdge + P8EST_EDGES * totalOrient; 1728 conn->tree_to_edge[P8EST_EDGES * (p - cStart) + p4estEdge] = e - eStart; 1729 } 1730 } 1731 PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure)); 1732 } 1733 } 1734 PetscCall(DMPlexRestoreTransitiveClosure(dm,e,PETSC_FALSE,&starSize,&star)); 1735 } 1736 PetscCall(PetscSectionDestroy(&ett)); 1737 #endif 1738 1739 /* 4: visit every vertex */ 1740 conn->ctt_offset[0] = 0; 1741 for (v = vStart; v < vEnd; v++) { 1742 PetscInt off, s; 1743 1744 PetscCall(PetscSectionGetOffset(ctt,v,&off)); 1745 conn->ctt_offset[v - vStart] = (p4est_topidx_t) off; 1746 PetscCall(DMPlexGetTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star)); 1747 for (s = 0; s < starSize; s++) { 1748 PetscInt p = star[2 * s]; 1749 1750 if (p >= cStart && p < cEnd) { 1751 PetscCall(DMPlexGetTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure)); 1752 PetscCheck(closureSize == P4EST_INSUL,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Non-standard closure"); 1753 for (c = 0; c < P4EST_CHILDREN; c++) { 1754 PetscInt cellVert = closure[2 * (c + vertOff)]; 1755 1756 if (cellVert == v) { 1757 PetscInt p4estVert = PetscVertToP4estVert[c]; 1758 1759 conn->corner_to_tree[off] = (p4est_locidx_t) (p - cStart); 1760 conn->corner_to_corner[off++] = (int8_t) p4estVert; 1761 conn->tree_to_corner[P4EST_CHILDREN * (p - cStart) + p4estVert] = v - vStart; 1762 } 1763 } 1764 PetscCall(DMPlexRestoreTransitiveClosure(dm,p,PETSC_TRUE,&closureSize,&closure)); 1765 } 1766 } 1767 PetscCall(DMPlexRestoreTransitiveClosure(dm,v,PETSC_FALSE,&starSize,&star)); 1768 } 1769 PetscCall(PetscSectionDestroy(&ctt)); 1770 1771 /* 5: Compute the coordinates */ 1772 { 1773 PetscInt coordDim; 1774 Vec coordVec; 1775 PetscSection coordSec; 1776 PetscBool localized; 1777 1778 PetscCall(DMGetCoordinateDim(dm, &coordDim)); 1779 PetscCall(DMGetCoordinatesLocal(dm, &coordVec)); 1780 PetscCall(DMGetCoordinatesLocalizedLocal(dm, &localized)); 1781 PetscCall(DMGetCoordinateSection(dm, &coordSec)); 1782 for (c = cStart; c < cEnd; c++) { 1783 PetscInt dof; 1784 PetscScalar *cellCoords = NULL; 1785 1786 PetscCall(DMPlexVecGetClosure(dm, coordSec, coordVec, c, &dof, &cellCoords)); 1787 PetscCheck(localized || dof == P4EST_CHILDREN * coordDim,PETSC_COMM_SELF,PETSC_ERR_ARG_WRONG,"Need coordinates at the corners: (dof) %" PetscInt_FMT " != %d * %" PetscInt_FMT " (sdim)", dof, P4EST_CHILDREN, coordDim); 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(DMPlexVecRestoreClosure(dm, coordSec, coordVec, c, &dof, &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; 3905 Vec coordinates, cVec; 3906 PetscSection oldSection, baseSection = NULL, newSection; 3907 const PetscScalar *coords; 3908 PetscScalar *coords2; 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 isper, baseLocalized = PETSC_FALSE; 3916 3917 PetscFunctionBegin; 3918 PetscCall(DMGetPeriodicity(dm,&isper,NULL,NULL,NULL)); 3919 if (!isper) PetscFunctionReturn(0); 3920 /* we localize on all cells if we don't have a base DM or the base DM coordinates have not been localized */ 3921 PetscCall(DMGetCoordinateDim(dm, &cDim)); 3922 cdof = P4EST_CHILDREN*cDim; 3923 PetscCall(DMForestGetBaseDM(dm,&base)); 3924 if (base) { 3925 PetscCall(DMGetCoordinatesLocalized(base,&baseLocalized)); 3926 } 3927 if (!baseLocalized) base = NULL; 3928 PetscCall(DMPlexGetChart(plex, &newStart, &newEnd)); 3929 3930 PetscCall(DMForestGetPartitionOverlap(dm,&overlap)); 3931 PetscCall(PetscCalloc1(overlap ? newEnd - newStart : 0,&localize)); 3932 3933 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject) dm), &newSection)); 3934 PetscCall(PetscSectionSetNumFields(newSection, 1)); 3935 PetscCall(PetscSectionSetFieldComponents(newSection, 0, cDim)); 3936 PetscCall(PetscSectionSetChart(newSection, newStart, newEnd)); 3937 3938 PetscCall(DMGetCoordinateSection(plex, &oldSection)); 3939 if (base) PetscCall(DMGetCoordinateSection(base, &baseSection)); 3940 PetscCall(DMPlexGetDepthStratum(plex,0,&vStart,&vEnd)); 3941 for (v = vStart; v < vEnd; ++v) { 3942 PetscCall(PetscSectionGetDof(oldSection, v, &dof)); 3943 PetscCall(PetscSectionSetDof(newSection, v, dof)); 3944 PetscCall(PetscSectionSetFieldDof(newSection, v, 0, dof)); 3945 if (overlap) localize[v] = dof; 3946 } 3947 3948 forest = (DM_Forest*) dm->data; 3949 pforest = (DM_Forest_pforest*) forest->data; 3950 cLocalStart = pforest->cLocalStart; 3951 cLocalEnd = pforest->cLocalEnd; 3952 flt = pforest->forest->first_local_tree; 3953 llt = pforest->forest->last_local_tree; 3954 trees = (p4est_tree_t*) pforest->forest->trees->array; 3955 3956 cp = 0; 3957 PetscCall(DMPlexGetHeightStratum(plex,0,&cStart,&cEnd)); 3958 PetscCall(DMPlexGetGhostCellStratum(plex,&cEndInterior,NULL)); 3959 cEnd = cEndInterior < 0 ? cEnd : cEndInterior; 3960 PetscCall(PetscMalloc1(cEnd-cStart,&coarsePoints)); 3961 if (cLocalStart > 0) { 3962 p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array; 3963 PetscInt count; 3964 3965 for (count = 0; count < cLocalStart; count++) { 3966 p4est_quadrant_t *quad = &ghosts[count]; 3967 coarsePoint = quad->p.which_tree; 3968 3969 if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof)); 3970 PetscCall(PetscSectionSetDof(newSection, count, cdof)); 3971 PetscCall(PetscSectionSetFieldDof(newSection, count, 0, cdof)); 3972 coarsePoints[cp++] = cdof ? coarsePoint : -1; 3973 if (overlap) localize[count] = cdof; 3974 } 3975 } 3976 for (t = flt; t <= llt; t++) { 3977 p4est_tree_t *tree = &(trees[t]); 3978 PetscInt offset = cLocalStart + tree->quadrants_offset; 3979 PetscInt numQuads = (PetscInt) tree->quadrants.elem_count; 3980 PetscInt i; 3981 3982 if (!numQuads) continue; 3983 coarsePoint = t; 3984 if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof)); 3985 for (i = 0; i < numQuads; i++) { 3986 PetscInt newCell = i + offset; 3987 3988 PetscCall(PetscSectionSetDof(newSection, newCell, cdof)); 3989 PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof)); 3990 coarsePoints[cp++] = cdof ? coarsePoint : -1; 3991 if (overlap) localize[newCell] = cdof; 3992 } 3993 } 3994 if (cLocalEnd - cLocalStart < cEnd - cStart) { 3995 p4est_quadrant_t *ghosts = (p4est_quadrant_t*) pforest->ghost->ghosts.array; 3996 PetscInt numGhosts = (PetscInt) pforest->ghost->ghosts.elem_count; 3997 PetscInt count; 3998 3999 for (count = 0; count < numGhosts - cLocalStart; count++) { 4000 p4est_quadrant_t *quad = &ghosts[count + cLocalStart]; 4001 coarsePoint = quad->p.which_tree; 4002 PetscInt newCell = count + cLocalEnd; 4003 4004 if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof)); 4005 PetscCall(PetscSectionSetDof(newSection, newCell, cdof)); 4006 PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof)); 4007 coarsePoints[cp++] = cdof ? coarsePoint : -1; 4008 if (overlap) localize[newCell] = cdof; 4009 } 4010 } 4011 PetscCheck(cp == cEnd - cStart,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Unexpected number of fine cells %" PetscInt_FMT " != %" PetscInt_FMT,cp,cEnd-cStart); 4012 4013 if (base) { /* we need to localize on all the cells in the star of the coarse cell vertices */ 4014 PetscInt *closure = NULL, closureSize; 4015 PetscInt p, i, c, vStartBase, vEndBase, cStartBase, cEndBase; 4016 4017 PetscCall(DMPlexGetHeightStratum(base,0,&cStartBase,&cEndBase)); 4018 PetscCall(DMPlexGetDepthStratum(base,0,&vStartBase,&vEndBase)); 4019 for (p = cStart; p < cEnd; p++) { 4020 coarsePoint = coarsePoints[p-cStart]; 4021 if (coarsePoint < 0) continue; 4022 if (baseSection) PetscCall(PetscSectionGetFieldDof(baseSection, coarsePoint, 0, &cdof)); 4023 PetscCall(DMPlexGetTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure)); 4024 for (c = 0; c < closureSize; c++) { 4025 PetscInt *star = NULL, starSize; 4026 PetscInt j, v = closure[2 * c]; 4027 4028 if (v < vStartBase || v > vEndBase) continue; 4029 PetscCall(DMPlexGetTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star)); 4030 for (j = 0; j < starSize; j++) { 4031 PetscInt cell = star[2 * j]; 4032 4033 if (cStartBase <= cell && cell < cEndBase) { 4034 p4est_tree_t *tree; 4035 PetscInt offset,numQuads; 4036 4037 if (cell < flt || cell > llt) continue; 4038 tree = &(trees[cell]); 4039 offset = cLocalStart + tree->quadrants_offset; 4040 numQuads = (PetscInt) tree->quadrants.elem_count; 4041 for (i = 0; i < numQuads; i++) { 4042 PetscInt newCell = i + offset; 4043 4044 PetscCall(PetscSectionSetDof(newSection, newCell, cdof)); 4045 PetscCall(PetscSectionSetFieldDof(newSection, newCell, 0, cdof)); 4046 if (overlap) localize[newCell] = cdof; 4047 } 4048 } 4049 } 4050 PetscCall(DMPlexRestoreTransitiveClosure(base,v,PETSC_FALSE,&starSize,&star)); 4051 } 4052 PetscCall(DMPlexRestoreTransitiveClosure(base,coarsePoint,PETSC_TRUE,&closureSize,&closure)); 4053 } 4054 } 4055 PetscCall(PetscFree(coarsePoints)); 4056 4057 /* final consensus with overlap */ 4058 if (overlap) { 4059 PetscSF sf; 4060 PetscInt *localizeGlobal; 4061 4062 PetscCall(DMGetPointSF(plex,&sf)); 4063 PetscCall(PetscMalloc1(newEnd-newStart,&localizeGlobal)); 4064 for (v = newStart; v < newEnd; v++) localizeGlobal[v - newStart] = localize[v - newStart]; 4065 PetscCall(PetscSFBcastBegin(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE)); 4066 PetscCall(PetscSFBcastEnd(sf,MPIU_INT,localize,localizeGlobal,MPI_REPLACE)); 4067 for (v = newStart; v < newEnd; v++) { 4068 PetscCall(PetscSectionSetDof(newSection, v, localizeGlobal[v-newStart])); 4069 PetscCall(PetscSectionSetFieldDof(newSection, v, 0, localizeGlobal[v-newStart])); 4070 } 4071 PetscCall(PetscFree(localizeGlobal)); 4072 } 4073 PetscCall(PetscFree(localize)); 4074 PetscCall(PetscSectionSetUp(newSection)); 4075 PetscCall(PetscObjectReference((PetscObject)oldSection)); 4076 PetscCall(DMSetCoordinateSection(plex, cDim, newSection)); 4077 PetscCall(PetscSectionGetStorageSize(newSection, &v)); 4078 PetscCall(VecCreate(PETSC_COMM_SELF, &cVec)); 4079 PetscCall(PetscObjectSetName((PetscObject)cVec,"coordinates")); 4080 PetscCall(VecSetBlockSize(cVec, cDim)); 4081 PetscCall(VecSetSizes(cVec, v, PETSC_DETERMINE)); 4082 PetscCall(VecSetType(cVec, VECSTANDARD)); 4083 PetscCall(VecSet(cVec, PETSC_MIN_REAL)); 4084 4085 /* Copy over vertex coordinates */ 4086 PetscCall(DMGetCoordinatesLocal(plex, &coordinates)); 4087 PetscCheck(coordinates,PetscObjectComm((PetscObject)plex),PETSC_ERR_SUP,"Missing local coordinates vector"); 4088 PetscCall(VecGetArray(cVec, &coords2)); 4089 PetscCall(VecGetArrayRead(coordinates, &coords)); 4090 for (v = vStart; v < vEnd; ++v) { 4091 PetscInt d, off,off2; 4092 4093 PetscCall(PetscSectionGetDof(oldSection, v, &dof)); 4094 PetscCall(PetscSectionGetOffset(oldSection, v, &off)); 4095 PetscCall(PetscSectionGetOffset(newSection, v, &off2)); 4096 for (d = 0; d < dof; ++d) coords2[off2+d] = coords[off+d]; 4097 } 4098 PetscCall(VecRestoreArrayRead(coordinates, &coords)); 4099 4100 /* Localize coordinates on cells if needed */ 4101 for (t = flt; t <= llt; t++) { 4102 p4est_tree_t *tree = &(trees[t]); 4103 const double *v = pforest->topo->conn->vertices; 4104 p4est_quadrant_t *quads = (p4est_quadrant_t*) tree->quadrants.array; 4105 PetscInt offset = cLocalStart + tree->quadrants_offset; 4106 PetscInt numQuads = (PetscInt) tree->quadrants.elem_count; 4107 p4est_topidx_t vt[8] = {0,0,0,0,0,0,0,0}; 4108 PetscInt i,k; 4109 4110 if (!numQuads) continue; 4111 for (k = 0; k < P4EST_CHILDREN; ++k) { 4112 vt[k] = pforest->topo->conn->tree_to_vertex[t * P4EST_CHILDREN + k]; 4113 } 4114 4115 for (i = 0; i < numQuads; i++) { 4116 p4est_quadrant_t *quad = &quads[i]; 4117 const PetscReal intsize = 1.0 / P4EST_ROOT_LEN; 4118 PetscReal h2; 4119 PetscScalar xyz[3]; 4120 #ifdef P4_TO_P8 4121 PetscInt zi; 4122 #endif 4123 PetscInt yi,xi; 4124 PetscInt off2; 4125 PetscInt newCell = i + offset; 4126 4127 PetscCall(PetscSectionGetFieldDof(newSection, newCell, 0, &cdof)); 4128 if (!cdof) continue; 4129 4130 h2 = .5 * intsize * P4EST_QUADRANT_LEN (quad->level); 4131 k = 0; 4132 PetscCall(PetscSectionGetOffset(newSection, newCell, &off2)); 4133 #ifdef P4_TO_P8 4134 for (zi = 0; zi < 2; ++zi) { 4135 const PetscReal eta_z = intsize * quad->z + h2 * (1. + (zi * 2 - 1)); 4136 #else 4137 { 4138 const PetscReal eta_z = 0.0; 4139 #endif 4140 for (yi = 0; yi < 2; ++yi) { 4141 const PetscReal eta_y = intsize * quad->y + h2 * (1. + (yi * 2 - 1)); 4142 for (xi = 0; xi < 2; ++xi) { 4143 const PetscReal eta_x = intsize * quad->x + h2 * (1. + (xi * 2 - 1)); 4144 PetscInt j; 4145 4146 for (j = 0; j < 3; ++j) { 4147 xyz[j] = ((1. - eta_z) * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[0] + j] + 4148 eta_x * v[3 * vt[1] + j]) + 4149 eta_y * ((1. - eta_x) * v[3 * vt[2] + j] + 4150 eta_x * v[3 * vt[3] + j])) 4151 + eta_z * ((1. - eta_y) * ((1. - eta_x) * v[3 * vt[4] + j] + 4152 eta_x * v[3 * vt[5] + j]) + 4153 eta_y * ((1. - eta_x) * v[3 * vt[6] + j] + 4154 eta_x * v[3 * vt[7] + j]))); 4155 } 4156 for (j = 0; j < cDim; ++j) coords2[off2 + cDim*P4estVertToPetscVert[k] + j] = xyz[j]; 4157 ++k; 4158 } 4159 } 4160 } 4161 } 4162 } 4163 PetscCall(VecRestoreArray(cVec, &coords2)); 4164 PetscCall(DMSetCoordinatesLocal(plex, cVec)); 4165 PetscCall(VecDestroy(&cVec)); 4166 PetscCall(PetscSectionDestroy(&newSection)); 4167 PetscCall(PetscSectionDestroy(&oldSection)); 4168 PetscFunctionReturn(0); 4169 } 4170 4171 #define DMForestClearAdaptivityForest_pforest _append_pforest(DMForestClearAdaptivityForest) 4172 static PetscErrorCode DMForestClearAdaptivityForest_pforest(DM dm) 4173 { 4174 DM_Forest *forest; 4175 DM_Forest_pforest *pforest; 4176 4177 PetscFunctionBegin; 4178 forest = (DM_Forest*) dm->data; 4179 pforest = (DM_Forest_pforest *) forest->data; 4180 PetscCall(PetscSFDestroy(&(pforest->pointAdaptToSelfSF))); 4181 PetscCall(PetscSFDestroy(&(pforest->pointSelfToAdaptSF))); 4182 PetscCall(PetscFree(pforest->pointAdaptToSelfCids)); 4183 PetscCall(PetscFree(pforest->pointSelfToAdaptCids)); 4184 PetscFunctionReturn(0); 4185 } 4186 4187 static PetscErrorCode DMConvert_pforest_plex(DM dm, DMType newtype, DM *plex) 4188 { 4189 DM_Forest *forest; 4190 DM_Forest_pforest *pforest; 4191 DM refTree, newPlex, base; 4192 PetscInt adjDim, adjCodim, coordDim; 4193 MPI_Comm comm; 4194 PetscBool isPforest; 4195 PetscInt dim; 4196 PetscInt overlap; 4197 p4est_connect_type_t ctype; 4198 p4est_locidx_t first_local_quad = -1; 4199 sc_array_t *points_per_dim, *cone_sizes, *cones, *cone_orientations, *coords, *children, *parents, *childids, *leaves, *remotes; 4200 PetscSection parentSection; 4201 PetscSF pointSF; 4202 size_t zz, count; 4203 PetscInt pStart, pEnd; 4204 DMLabel ghostLabelBase = NULL; 4205 4206 PetscFunctionBegin; 4207 4208 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4209 comm = PetscObjectComm((PetscObject)dm); 4210 PetscCall(PetscObjectTypeCompare((PetscObject)dm,DMPFOREST,&isPforest)); 4211 PetscCheck(isPforest,comm,PETSC_ERR_ARG_WRONG,"Expected DM type %s, got %s",DMPFOREST,((PetscObject)dm)->type_name); 4212 PetscCall(DMGetDimension(dm,&dim)); 4213 PetscCheck(dim == P4EST_DIM,comm,PETSC_ERR_ARG_WRONG,"Expected DM dimension %d, got %" PetscInt_FMT,P4EST_DIM,dim); 4214 forest = (DM_Forest*) dm->data; 4215 pforest = (DM_Forest_pforest*) forest->data; 4216 PetscCall(DMForestGetBaseDM(dm,&base)); 4217 if (base) { 4218 PetscCall(DMGetLabel(base,"ghost",&ghostLabelBase)); 4219 } 4220 if (!pforest->plex) { 4221 PetscMPIInt size; 4222 4223 PetscCallMPI(MPI_Comm_size(comm,&size)); 4224 PetscCall(DMCreate(comm,&newPlex)); 4225 PetscCall(DMSetType(newPlex,DMPLEX)); 4226 PetscCall(DMSetMatType(newPlex,dm->mattype)); 4227 /* share labels */ 4228 PetscCall(DMCopyLabels(dm, newPlex, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL)); 4229 PetscCall(DMForestGetAdjacencyDimension(dm,&adjDim)); 4230 PetscCall(DMForestGetAdjacencyCodimension(dm,&adjCodim)); 4231 PetscCall(DMGetCoordinateDim(dm,&coordDim)); 4232 if (adjDim == 0) { 4233 ctype = P4EST_CONNECT_FULL; 4234 } else if (adjCodim == 1) { 4235 ctype = P4EST_CONNECT_FACE; 4236 #if defined(P4_TO_P8) 4237 } else if (adjDim == 1) { 4238 ctype = P8EST_CONNECT_EDGE; 4239 #endif 4240 } else { 4241 SETERRQ(PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Invalid adjacency dimension %" PetscInt_FMT,adjDim); 4242 } 4243 PetscCheck(ctype == P4EST_CONNECT_FULL,PetscObjectComm((PetscObject)dm),PETSC_ERR_ARG_WRONG,"Adjacency dimension %" PetscInt_FMT " / codimension %" PetscInt_FMT " not supported yet",adjDim,adjCodim); 4244 PetscCall(DMForestGetPartitionOverlap(dm,&overlap)); 4245 PetscCall(DMPlexSetOverlap_Plex(newPlex,NULL,overlap)); 4246 4247 points_per_dim = sc_array_new(sizeof(p4est_locidx_t)); 4248 cone_sizes = sc_array_new(sizeof(p4est_locidx_t)); 4249 cones = sc_array_new(sizeof(p4est_locidx_t)); 4250 cone_orientations = sc_array_new(sizeof(p4est_locidx_t)); 4251 coords = sc_array_new(3 * sizeof(double)); 4252 children = sc_array_new(sizeof(p4est_locidx_t)); 4253 parents = sc_array_new(sizeof(p4est_locidx_t)); 4254 childids = sc_array_new(sizeof(p4est_locidx_t)); 4255 leaves = sc_array_new(sizeof(p4est_locidx_t)); 4256 remotes = sc_array_new(2 * sizeof(p4est_locidx_t)); 4257 4258 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)); 4259 4260 pforest->cLocalStart = (PetscInt) first_local_quad; 4261 pforest->cLocalEnd = pforest->cLocalStart + (PetscInt) pforest->forest->local_num_quadrants; 4262 PetscCall(locidx_to_PetscInt(points_per_dim)); 4263 PetscCall(locidx_to_PetscInt(cone_sizes)); 4264 PetscCall(locidx_to_PetscInt(cones)); 4265 PetscCall(locidx_to_PetscInt(cone_orientations)); 4266 PetscCall(coords_double_to_PetscScalar(coords, coordDim)); 4267 PetscCall(locidx_to_PetscInt(children)); 4268 PetscCall(locidx_to_PetscInt(parents)); 4269 PetscCall(locidx_to_PetscInt(childids)); 4270 PetscCall(locidx_to_PetscInt(leaves)); 4271 PetscCall(locidx_pair_to_PetscSFNode(remotes)); 4272 4273 PetscCall(DMSetDimension(newPlex,P4EST_DIM)); 4274 PetscCall(DMSetCoordinateDim(newPlex,coordDim)); 4275 PetscCall(DMPlexSetMaxProjectionHeight(newPlex,P4EST_DIM - 1)); 4276 PetscCall(DMPlexCreateFromDAG(newPlex,P4EST_DIM,(PetscInt*)points_per_dim->array,(PetscInt*)cone_sizes->array,(PetscInt*)cones->array,(PetscInt*)cone_orientations->array,(PetscScalar*)coords->array)); 4277 PetscCall(DMPlexConvertOldOrientations_Internal(newPlex)); 4278 PetscCall(DMCreateReferenceTree_pforest(comm,&refTree)); 4279 PetscCall(DMPlexSetReferenceTree(newPlex,refTree)); 4280 PetscCall(PetscSectionCreate(comm,&parentSection)); 4281 PetscCall(DMPlexGetChart(newPlex,&pStart,&pEnd)); 4282 PetscCall(PetscSectionSetChart(parentSection,pStart,pEnd)); 4283 count = children->elem_count; 4284 for (zz = 0; zz < count; zz++) { 4285 PetscInt child = *((PetscInt*) sc_array_index(children,zz)); 4286 4287 PetscCall(PetscSectionSetDof(parentSection,child,1)); 4288 } 4289 PetscCall(PetscSectionSetUp(parentSection)); 4290 PetscCall(DMPlexSetTree(newPlex,parentSection,(PetscInt*)parents->array,(PetscInt*)childids->array)); 4291 PetscCall(PetscSectionDestroy(&parentSection)); 4292 PetscCall(PetscSFCreate(comm,&pointSF)); 4293 /* 4294 These arrays defining the sf are from the p4est library, but the code there shows the leaves being populated in increasing order. 4295 https://gitlab.com/petsc/petsc/merge_requests/2248#note_240186391 4296 */ 4297 PetscCall(PetscSFSetGraph(pointSF,pEnd - pStart,(PetscInt)leaves->elem_count,(PetscInt*)leaves->array,PETSC_COPY_VALUES,(PetscSFNode*)remotes->array,PETSC_COPY_VALUES)); 4298 PetscCall(DMSetPointSF(newPlex,pointSF)); 4299 PetscCall(DMSetPointSF(dm,pointSF)); 4300 { 4301 DM coordDM; 4302 4303 PetscCall(DMGetCoordinateDM(newPlex,&coordDM)); 4304 PetscCall(DMSetPointSF(coordDM,pointSF)); 4305 } 4306 PetscCall(PetscSFDestroy(&pointSF)); 4307 sc_array_destroy (points_per_dim); 4308 sc_array_destroy (cone_sizes); 4309 sc_array_destroy (cones); 4310 sc_array_destroy (cone_orientations); 4311 sc_array_destroy (coords); 4312 sc_array_destroy (children); 4313 sc_array_destroy (parents); 4314 sc_array_destroy (childids); 4315 sc_array_destroy (leaves); 4316 sc_array_destroy (remotes); 4317 4318 { 4319 PetscBool isper; 4320 const PetscReal *maxCell, *L; 4321 const DMBoundaryType *bd; 4322 4323 PetscCall(DMGetPeriodicity(dm,&isper,&maxCell,&L,&bd)); 4324 PetscCall(DMSetPeriodicity(newPlex,isper,maxCell,L,bd)); 4325 PetscCall(DMPforestLocalizeCoordinates(dm,newPlex)); 4326 } 4327 4328 if (overlap > 0) { /* the p4est routine can't set all of the coordinates in its routine if there is overlap */ 4329 Vec coordsGlobal, coordsLocal; 4330 const PetscScalar *globalArray; 4331 PetscScalar *localArray; 4332 PetscSF coordSF; 4333 DM coordDM; 4334 4335 PetscCall(DMGetCoordinateDM(newPlex,&coordDM)); 4336 PetscCall(DMGetSectionSF(coordDM,&coordSF)); 4337 PetscCall(DMGetCoordinates(newPlex, &coordsGlobal)); 4338 PetscCall(DMGetCoordinatesLocal(newPlex, &coordsLocal)); 4339 PetscCall(VecGetArrayRead(coordsGlobal, &globalArray)); 4340 PetscCall(VecGetArray(coordsLocal, &localArray)); 4341 PetscCall(PetscSFBcastBegin(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE)); 4342 PetscCall(PetscSFBcastEnd(coordSF,MPIU_SCALAR,globalArray,localArray,MPI_REPLACE)); 4343 PetscCall(VecRestoreArray(coordsLocal, &localArray)); 4344 PetscCall(VecRestoreArrayRead(coordsGlobal, &globalArray)); 4345 PetscCall(DMSetCoordinatesLocal(newPlex, coordsLocal)); 4346 } 4347 PetscCall(DMPforestMapCoordinates(dm,newPlex)); 4348 4349 pforest->plex = newPlex; 4350 4351 /* copy labels */ 4352 PetscCall(DMPforestLabelsFinalize(dm,newPlex)); 4353 4354 if (ghostLabelBase || pforest->ghostName) { /* we have to do this after copying labels because the labels drive the construction of ghost cells */ 4355 PetscInt numAdded; 4356 DM newPlexGhosted; 4357 void *ctx; 4358 4359 PetscCall(DMPlexConstructGhostCells(newPlex,pforest->ghostName,&numAdded,&newPlexGhosted)); 4360 PetscCall(DMGetApplicationContext(newPlex,&ctx)); 4361 PetscCall(DMSetApplicationContext(newPlexGhosted,ctx)); 4362 /* we want the sf for the ghost dm to be the one for the p4est dm as well */ 4363 PetscCall(DMGetPointSF(newPlexGhosted,&pointSF)); 4364 PetscCall(DMSetPointSF(dm,pointSF)); 4365 PetscCall(DMDestroy(&newPlex)); 4366 PetscCall(DMPlexSetReferenceTree(newPlexGhosted,refTree)); 4367 PetscCall(DMForestClearAdaptivityForest_pforest(dm)); 4368 newPlex = newPlexGhosted; 4369 4370 /* share the labels back */ 4371 PetscCall(DMDestroyLabelLinkList_Internal(dm)); 4372 PetscCall(DMCopyLabels(newPlex, dm, PETSC_OWN_POINTER, PETSC_TRUE, DM_COPY_LABELS_FAIL)); 4373 pforest->plex = newPlex; 4374 } 4375 PetscCall(DMDestroy(&refTree)); 4376 if (dm->setfromoptionscalled) { 4377 4378 PetscObjectOptionsBegin((PetscObject)newPlex); 4379 PetscCall(DMSetFromOptions_NonRefinement_Plex(PetscOptionsObject,newPlex)); 4380 PetscCall(PetscObjectProcessOptionsHandlers(PetscOptionsObject,(PetscObject)newPlex)); 4381 PetscOptionsEnd(); 4382 } 4383 PetscCall(DMViewFromOptions(newPlex,NULL,"-dm_p4est_plex_view")); 4384 { 4385 PetscSection coordsSec; 4386 Vec coords; 4387 PetscInt cDim; 4388 4389 PetscCall(DMGetCoordinateDim(newPlex,&cDim)); 4390 PetscCall(DMGetCoordinateSection(newPlex,&coordsSec)); 4391 PetscCall(DMSetCoordinateSection(dm,cDim,coordsSec)); 4392 PetscCall(DMGetCoordinatesLocal(newPlex,&coords)); 4393 PetscCall(DMSetCoordinatesLocal(dm,coords)); 4394 } 4395 } 4396 newPlex = pforest->plex; 4397 if (plex) { 4398 DM coordDM; 4399 4400 PetscCall(DMClone(newPlex,plex)); 4401 PetscCall(DMGetCoordinateDM(newPlex,&coordDM)); 4402 PetscCall(DMSetCoordinateDM(*plex,coordDM)); 4403 PetscCall(DMShareDiscretization(dm,*plex)); 4404 } 4405 PetscFunctionReturn(0); 4406 } 4407 4408 static PetscErrorCode DMSetFromOptions_pforest(PetscOptionItems *PetscOptionsObject,DM dm) 4409 { 4410 DM_Forest_pforest *pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data; 4411 char stringBuffer[256]; 4412 PetscBool flg; 4413 4414 PetscFunctionBegin; 4415 PetscCall(DMSetFromOptions_Forest(PetscOptionsObject,dm)); 4416 PetscOptionsHeadBegin(PetscOptionsObject,"DM" P4EST_STRING " options"); 4417 PetscCall(PetscOptionsBool("-dm_p4est_partition_for_coarsening","partition forest to allow for coarsening","DMP4estSetPartitionForCoarsening",pforest->partition_for_coarsening,&(pforest->partition_for_coarsening),NULL)); 4418 PetscCall(PetscOptionsString("-dm_p4est_ghost_label_name","the name of the ghost label when converting from a DMPlex",NULL,NULL,stringBuffer,sizeof(stringBuffer),&flg)); 4419 PetscOptionsHeadEnd(); 4420 if (flg) { 4421 PetscCall(PetscFree(pforest->ghostName)); 4422 PetscCall(PetscStrallocpy(stringBuffer,&pforest->ghostName)); 4423 } 4424 PetscFunctionReturn(0); 4425 } 4426 4427 #if !defined(P4_TO_P8) 4428 #define DMPforestGetPartitionForCoarsening DMP4estGetPartitionForCoarsening 4429 #define DMPforestSetPartitionForCoarsening DMP4estSetPartitionForCoarsening 4430 #else 4431 #define DMPforestGetPartitionForCoarsening DMP8estGetPartitionForCoarsening 4432 #define DMPforestSetPartitionForCoarsening DMP8estSetPartitionForCoarsening 4433 #endif 4434 4435 PETSC_EXTERN PetscErrorCode DMPforestGetPartitionForCoarsening(DM dm, PetscBool *flg) 4436 { 4437 DM_Forest_pforest *pforest; 4438 4439 PetscFunctionBegin; 4440 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4441 pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data; 4442 *flg = pforest->partition_for_coarsening; 4443 PetscFunctionReturn(0); 4444 } 4445 4446 PETSC_EXTERN PetscErrorCode DMPforestSetPartitionForCoarsening(DM dm, PetscBool flg) 4447 { 4448 DM_Forest_pforest *pforest; 4449 4450 PetscFunctionBegin; 4451 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4452 pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data; 4453 pforest->partition_for_coarsening = flg; 4454 PetscFunctionReturn(0); 4455 } 4456 4457 static PetscErrorCode DMPforestGetPlex(DM dm,DM *plex) 4458 { 4459 DM_Forest_pforest *pforest; 4460 4461 PetscFunctionBegin; 4462 if (plex) *plex = NULL; 4463 PetscCall(DMSetUp(dm)); 4464 pforest = (DM_Forest_pforest*) ((DM_Forest*) dm->data)->data; 4465 if (!pforest->plex) { 4466 PetscCall(DMConvert_pforest_plex(dm,DMPLEX,NULL)); 4467 } 4468 PetscCall(DMShareDiscretization(dm,pforest->plex)); 4469 if (plex) *plex = pforest->plex; 4470 PetscFunctionReturn(0); 4471 } 4472 4473 #define DMCreateInterpolation_pforest _append_pforest(DMCreateInterpolation) 4474 static PetscErrorCode DMCreateInterpolation_pforest(DM dmCoarse, DM dmFine, Mat *interpolation, Vec *scaling) 4475 { 4476 PetscSection gsc, gsf; 4477 PetscInt m, n; 4478 DM cdm; 4479 4480 PetscFunctionBegin; 4481 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 4482 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &m)); 4483 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 4484 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &n)); 4485 4486 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), interpolation)); 4487 PetscCall(MatSetSizes(*interpolation, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 4488 PetscCall(MatSetType(*interpolation, MATAIJ)); 4489 4490 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 4491 PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only interpolation from coarse DM for now"); 4492 4493 { 4494 DM plexF, plexC; 4495 PetscSF sf; 4496 PetscInt *cids; 4497 PetscInt dofPerDim[4] = {1,1,1,1}; 4498 4499 PetscCall(DMPforestGetPlex(dmCoarse,&plexC)); 4500 PetscCall(DMPforestGetPlex(dmFine,&plexF)); 4501 PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids)); 4502 PetscCall(PetscSFSetUp(sf)); 4503 PetscCall(DMPlexComputeInterpolatorTree(plexC, plexF, sf, cids, *interpolation)); 4504 PetscCall(PetscSFDestroy(&sf)); 4505 PetscCall(PetscFree(cids)); 4506 } 4507 PetscCall(MatViewFromOptions(*interpolation, NULL, "-interp_mat_view")); 4508 /* Use naive scaling */ 4509 PetscCall(DMCreateInterpolationScale(dmCoarse, dmFine, *interpolation, scaling)); 4510 PetscFunctionReturn(0); 4511 } 4512 4513 #define DMCreateInjection_pforest _append_pforest(DMCreateInjection) 4514 static PetscErrorCode DMCreateInjection_pforest(DM dmCoarse, DM dmFine, Mat *injection) 4515 { 4516 PetscSection gsc, gsf; 4517 PetscInt m, n; 4518 DM cdm; 4519 4520 PetscFunctionBegin; 4521 PetscCall(DMGetGlobalSection(dmFine, &gsf)); 4522 PetscCall(PetscSectionGetConstrainedStorageSize(gsf, &n)); 4523 PetscCall(DMGetGlobalSection(dmCoarse, &gsc)); 4524 PetscCall(PetscSectionGetConstrainedStorageSize(gsc, &m)); 4525 4526 PetscCall(MatCreate(PetscObjectComm((PetscObject) dmFine), injection)); 4527 PetscCall(MatSetSizes(*injection, m, n, PETSC_DETERMINE, PETSC_DETERMINE)); 4528 PetscCall(MatSetType(*injection, MATAIJ)); 4529 4530 PetscCall(DMGetCoarseDM(dmFine, &cdm)); 4531 PetscCheck(cdm == dmCoarse,PetscObjectComm((PetscObject)dmFine),PETSC_ERR_SUP,"Only injection to coarse DM for now"); 4532 4533 { 4534 DM plexF, plexC; 4535 PetscSF sf; 4536 PetscInt *cids; 4537 PetscInt dofPerDim[4] = {1,1,1,1}; 4538 4539 PetscCall(DMPforestGetPlex(dmCoarse,&plexC)); 4540 PetscCall(DMPforestGetPlex(dmFine,&plexF)); 4541 PetscCall(DMPforestGetTransferSF_Internal(dmCoarse, dmFine, dofPerDim, &sf, PETSC_TRUE, &cids)); 4542 PetscCall(PetscSFSetUp(sf)); 4543 PetscCall(DMPlexComputeInjectorTree(plexC, plexF, sf, cids, *injection)); 4544 PetscCall(PetscSFDestroy(&sf)); 4545 PetscCall(PetscFree(cids)); 4546 } 4547 PetscCall(MatViewFromOptions(*injection, NULL, "-inject_mat_view")); 4548 /* Use naive scaling */ 4549 PetscFunctionReturn(0); 4550 } 4551 4552 #define DMForestTransferVecFromBase_pforest _append_pforest(DMForestTransferVecFromBase) 4553 static PetscErrorCode DMForestTransferVecFromBase_pforest(DM dm, Vec vecIn, Vec vecOut) 4554 { 4555 DM dmIn, dmVecIn, base, basec, plex, coarseDM; 4556 DM *hierarchy; 4557 PetscSF sfRed = NULL; 4558 PetscDS ds; 4559 Vec vecInLocal, vecOutLocal; 4560 DMLabel subpointMap; 4561 PetscInt minLevel, mh, n_hi, i; 4562 PetscBool hiforest, *hierarchy_forest; 4563 4564 PetscFunctionBegin; 4565 PetscCall(VecGetDM(vecIn,&dmVecIn)); 4566 PetscCall(DMGetDS(dmVecIn,&ds)); 4567 PetscCheck(ds,PetscObjectComm((PetscObject)dmVecIn),PETSC_ERR_SUP,"Cannot transfer without a PetscDS object"); 4568 { /* we cannot stick user contexts into function callbacks for DMProjectFieldLocal! */ 4569 PetscSection section; 4570 PetscInt Nf; 4571 4572 PetscCall(DMGetLocalSection(dmVecIn,§ion)); 4573 PetscCall(PetscSectionGetNumFields(section,&Nf)); 4574 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); 4575 } 4576 PetscCall(DMForestGetMinimumRefinement(dm,&minLevel)); 4577 PetscCheck(!minLevel,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Cannot transfer with minimum refinement set to %" PetscInt_FMT ". Rerun with DMForestSetMinimumRefinement(dm,0)",minLevel); 4578 PetscCall(DMForestGetBaseDM(dm,&base)); 4579 PetscCheck(base,PetscObjectComm((PetscObject)dm),PETSC_ERR_SUP,"Missing base DM"); 4580 4581 PetscCall(VecSet(vecOut,0.0)); 4582 if (dmVecIn == base) { /* sequential runs */ 4583 PetscCall(PetscObjectReference((PetscObject)vecIn)); 4584 } else { 4585 PetscSection secIn, secInRed; 4586 Vec vecInRed, vecInLocal; 4587 4588 PetscCall(PetscObjectQuery((PetscObject)base,"_base_migration_sf",(PetscObject*)&sfRed)); 4589 PetscCheck(sfRed,PETSC_COMM_SELF,PETSC_ERR_SUP,"Not the DM set with DMForestSetBaseDM()"); 4590 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmVecIn),&secInRed)); 4591 PetscCall(VecCreate(PETSC_COMM_SELF,&vecInRed)); 4592 PetscCall(DMGetLocalSection(dmVecIn,&secIn)); 4593 PetscCall(DMGetLocalVector(dmVecIn,&vecInLocal)); 4594 PetscCall(DMGlobalToLocalBegin(dmVecIn,vecIn,INSERT_VALUES,vecInLocal)); 4595 PetscCall(DMGlobalToLocalEnd(dmVecIn,vecIn,INSERT_VALUES,vecInLocal)); 4596 PetscCall(DMPlexDistributeField(dmVecIn,sfRed,secIn,vecInLocal,secInRed,vecInRed)); 4597 PetscCall(DMRestoreLocalVector(dmVecIn,&vecInLocal)); 4598 PetscCall(PetscSectionDestroy(&secInRed)); 4599 vecIn = vecInRed; 4600 } 4601 4602 /* we first search through the AdaptivityForest hierarchy 4603 once we found the first disconnected forest, we upsweep the DM hierarchy */ 4604 hiforest = PETSC_TRUE; 4605 4606 /* upsweep to the coarsest DM */ 4607 n_hi = 0; 4608 coarseDM = dm; 4609 do { 4610 PetscBool isforest; 4611 4612 dmIn = coarseDM; 4613 /* need to call DMSetUp to have the hierarchy recursively setup */ 4614 PetscCall(DMSetUp(dmIn)); 4615 PetscCall(DMIsForest(dmIn,&isforest)); 4616 PetscCheck(isforest,PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Cannot currently transfer through a mixed hierarchy! Found DM type %s",((PetscObject)dmIn)->type_name); 4617 coarseDM = NULL; 4618 if (hiforest) { 4619 PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM)); 4620 } 4621 if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */ 4622 hiforest = PETSC_FALSE; 4623 PetscCall(DMGetCoarseDM(dmIn,&coarseDM)); 4624 } 4625 n_hi++; 4626 } while (coarseDM); 4627 4628 PetscCall(PetscMalloc2(n_hi,&hierarchy,n_hi,&hierarchy_forest)); 4629 4630 i = 0; 4631 hiforest = PETSC_TRUE; 4632 coarseDM = dm; 4633 do { 4634 dmIn = coarseDM; 4635 coarseDM = NULL; 4636 if (hiforest) { 4637 PetscCall(DMForestGetAdaptivityForest(dmIn,&coarseDM)); 4638 } 4639 if (!coarseDM) { /* DMForest hierarchy ended, we keep upsweeping through the DM hierarchy */ 4640 hiforest = PETSC_FALSE; 4641 PetscCall(DMGetCoarseDM(dmIn,&coarseDM)); 4642 } 4643 i++; 4644 hierarchy[n_hi - i] = dmIn; 4645 } while (coarseDM); 4646 4647 /* project base vector on the coarsest forest (minimum refinement = 0) */ 4648 PetscCall(DMPforestGetPlex(dmIn,&plex)); 4649 4650 /* Check this plex is compatible with the base */ 4651 { 4652 IS gnum[2]; 4653 PetscInt ncells[2],gncells[2]; 4654 4655 PetscCall(DMPlexGetCellNumbering(base,&gnum[0])); 4656 PetscCall(DMPlexGetCellNumbering(plex,&gnum[1])); 4657 PetscCall(ISGetMinMax(gnum[0],NULL,&ncells[0])); 4658 PetscCall(ISGetMinMax(gnum[1],NULL,&ncells[1])); 4659 PetscCall(MPIU_Allreduce(ncells,gncells,2,MPIU_INT,MPI_MAX,PetscObjectComm((PetscObject)dm))); 4660 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); 4661 } 4662 4663 PetscCall(DMGetLabel(dmIn,"_forest_base_subpoint_map",&subpointMap)); 4664 PetscCheck(subpointMap,PETSC_COMM_SELF,PETSC_ERR_PLIB,"Missing _forest_base_subpoint_map label"); 4665 4666 PetscCall(DMPlexGetMaxProjectionHeight(base,&mh)); 4667 PetscCall(DMPlexSetMaxProjectionHeight(plex,mh)); 4668 4669 PetscCall(DMClone(base,&basec)); 4670 PetscCall(DMCopyDisc(dmVecIn,basec)); 4671 if (sfRed) { 4672 PetscCall(PetscObjectReference((PetscObject)vecIn)); 4673 vecInLocal = vecIn; 4674 } else { 4675 PetscCall(DMCreateLocalVector(basec,&vecInLocal)); 4676 PetscCall(DMGlobalToLocalBegin(basec,vecIn,INSERT_VALUES,vecInLocal)); 4677 PetscCall(DMGlobalToLocalEnd(basec,vecIn,INSERT_VALUES,vecInLocal)); 4678 } 4679 4680 PetscCall(DMGetLocalVector(dmIn,&vecOutLocal)); 4681 { /* get degrees of freedom ordered onto dmIn */ 4682 PetscSF basetocoarse; 4683 PetscInt bStart, bEnd, nroots; 4684 PetscInt iStart, iEnd, nleaves, leaf; 4685 PetscMPIInt rank; 4686 PetscSFNode *remotes; 4687 PetscSection secIn, secOut; 4688 PetscInt *remoteOffsets; 4689 PetscSF transferSF; 4690 const PetscScalar *inArray; 4691 PetscScalar *outArray; 4692 4693 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)basec), &rank)); 4694 PetscCall(DMPlexGetChart(basec, &bStart, &bEnd)); 4695 nroots = PetscMax(bEnd - bStart, 0); 4696 PetscCall(DMPlexGetChart(plex, &iStart, &iEnd)); 4697 nleaves = PetscMax(iEnd - iStart, 0); 4698 4699 PetscCall(PetscMalloc1(nleaves, &remotes)); 4700 for (leaf = iStart; leaf < iEnd; leaf++) { 4701 PetscInt index; 4702 4703 remotes[leaf - iStart].rank = rank; 4704 PetscCall(DMLabelGetValue(subpointMap, leaf, &index)); 4705 remotes[leaf - iStart].index = index; 4706 } 4707 4708 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)basec), &basetocoarse)); 4709 PetscCall(PetscSFSetGraph(basetocoarse, nroots, nleaves, NULL, PETSC_OWN_POINTER, remotes, PETSC_OWN_POINTER)); 4710 PetscCall(PetscSFSetUp(basetocoarse)); 4711 PetscCall(DMGetLocalSection(basec,&secIn)); 4712 PetscCall(PetscSectionCreate(PetscObjectComm((PetscObject)dmIn),&secOut)); 4713 PetscCall(PetscSFDistributeSection(basetocoarse, secIn, &remoteOffsets, secOut)); 4714 PetscCall(PetscSFCreateSectionSF(basetocoarse, secIn, remoteOffsets, secOut, &transferSF)); 4715 PetscCall(PetscFree(remoteOffsets)); 4716 PetscCall(VecGetArrayWrite(vecOutLocal, &outArray)); 4717 PetscCall(VecGetArrayRead(vecInLocal, &inArray)); 4718 PetscCall(PetscSFBcastBegin(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE)); 4719 PetscCall(PetscSFBcastEnd(transferSF, MPIU_SCALAR, inArray, outArray,MPI_REPLACE)); 4720 PetscCall(VecRestoreArrayRead(vecInLocal, &inArray)); 4721 PetscCall(VecRestoreArrayWrite(vecOutLocal, &outArray)); 4722 PetscCall(PetscSFDestroy(&transferSF)); 4723 PetscCall(PetscSectionDestroy(&secOut)); 4724 PetscCall(PetscSFDestroy(&basetocoarse)); 4725 } 4726 PetscCall(VecDestroy(&vecInLocal)); 4727 PetscCall(DMDestroy(&basec)); 4728 PetscCall(VecDestroy(&vecIn)); 4729 4730 /* output */ 4731 if (n_hi > 1) { /* downsweep the stored hierarchy */ 4732 Vec vecOut1, vecOut2; 4733 DM fineDM; 4734 4735 PetscCall(DMGetGlobalVector(dmIn,&vecOut1)); 4736 PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut1)); 4737 PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal)); 4738 for (i = 1; i < n_hi-1; i++) { 4739 fineDM = hierarchy[i]; 4740 PetscCall(DMGetGlobalVector(fineDM,&vecOut2)); 4741 PetscCall(DMForestTransferVec(dmIn,vecOut1,fineDM,vecOut2,PETSC_TRUE,0.0)); 4742 PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1)); 4743 vecOut1 = vecOut2; 4744 dmIn = fineDM; 4745 } 4746 PetscCall(DMForestTransferVec(dmIn,vecOut1,dm,vecOut,PETSC_TRUE,0.0)); 4747 PetscCall(DMRestoreGlobalVector(dmIn,&vecOut1)); 4748 } else { 4749 PetscCall(DMLocalToGlobal(dmIn,vecOutLocal,INSERT_VALUES,vecOut)); 4750 PetscCall(DMRestoreLocalVector(dmIn,&vecOutLocal)); 4751 } 4752 PetscCall(PetscFree2(hierarchy,hierarchy_forest)); 4753 PetscFunctionReturn(0); 4754 } 4755 4756 #define DMForestTransferVec_pforest _append_pforest(DMForestTransferVec) 4757 static PetscErrorCode DMForestTransferVec_pforest(DM dmIn, Vec vecIn, DM dmOut, Vec vecOut, PetscBool useBCs, PetscReal time) 4758 { 4759 DM adaptIn, adaptOut, plexIn, plexOut; 4760 DM_Forest *forestIn, *forestOut, *forestAdaptIn, *forestAdaptOut; 4761 PetscInt dofPerDim[] = {1, 1, 1, 1}; 4762 PetscSF inSF = NULL, outSF = NULL; 4763 PetscInt *inCids = NULL, *outCids = NULL; 4764 DMAdaptFlag purposeIn, purposeOut; 4765 4766 PetscFunctionBegin; 4767 forestOut = (DM_Forest *) dmOut->data; 4768 forestIn = (DM_Forest *) dmIn->data; 4769 4770 PetscCall(DMForestGetAdaptivityForest(dmOut,&adaptOut)); 4771 PetscCall(DMForestGetAdaptivityPurpose(dmOut,&purposeOut)); 4772 forestAdaptOut = adaptOut ? (DM_Forest *) adaptOut->data : NULL; 4773 4774 PetscCall(DMForestGetAdaptivityForest(dmIn,&adaptIn)); 4775 PetscCall(DMForestGetAdaptivityPurpose(dmIn,&purposeIn)); 4776 forestAdaptIn = adaptIn ? (DM_Forest *) adaptIn->data : NULL; 4777 4778 if (forestAdaptOut == forestIn) { 4779 switch (purposeOut) { 4780 case DM_ADAPT_REFINE: 4781 PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids)); 4782 PetscCall(PetscSFSetUp(inSF)); 4783 break; 4784 case DM_ADAPT_COARSEN: 4785 case DM_ADAPT_COARSEN_LAST: 4786 PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&outCids)); 4787 PetscCall(PetscSFSetUp(outSF)); 4788 break; 4789 default: 4790 PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids)); 4791 PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids)); 4792 PetscCall(PetscSFSetUp(inSF)); 4793 PetscCall(PetscSFSetUp(outSF)); 4794 } 4795 } else if (forestAdaptIn == forestOut) { 4796 switch (purposeIn) { 4797 case DM_ADAPT_REFINE: 4798 PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_TRUE,&inCids)); 4799 PetscCall(PetscSFSetUp(outSF)); 4800 break; 4801 case DM_ADAPT_COARSEN: 4802 case DM_ADAPT_COARSEN_LAST: 4803 PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids)); 4804 PetscCall(PetscSFSetUp(inSF)); 4805 break; 4806 default: 4807 PetscCall(DMPforestGetTransferSF_Internal(dmIn,dmOut,dofPerDim,&inSF,PETSC_TRUE,&inCids)); 4808 PetscCall(DMPforestGetTransferSF_Internal(dmOut,dmIn,dofPerDim,&outSF,PETSC_FALSE,&outCids)); 4809 PetscCall(PetscSFSetUp(inSF)); 4810 PetscCall(PetscSFSetUp(outSF)); 4811 } 4812 } else SETERRQ(PetscObjectComm((PetscObject)dmIn),PETSC_ERR_SUP,"Only support transfer from pre-adaptivity to post-adaptivity right now"); 4813 PetscCall(DMPforestGetPlex(dmIn,&plexIn)); 4814 PetscCall(DMPforestGetPlex(dmOut,&plexOut)); 4815 4816 PetscCall(DMPlexTransferVecTree(plexIn,vecIn,plexOut,vecOut,inSF,outSF,inCids,outCids,useBCs,time)); 4817 PetscCall(PetscFree(inCids)); 4818 PetscCall(PetscFree(outCids)); 4819 PetscCall(PetscSFDestroy(&inSF)); 4820 PetscCall(PetscSFDestroy(&outSF)); 4821 PetscCall(PetscFree(inCids)); 4822 PetscCall(PetscFree(outCids)); 4823 PetscFunctionReturn(0); 4824 } 4825 4826 #define DMCreateCoordinateDM_pforest _append_pforest(DMCreateCoordinateDM) 4827 static PetscErrorCode DMCreateCoordinateDM_pforest(DM dm,DM *cdm) 4828 { 4829 DM plex; 4830 4831 PetscFunctionBegin; 4832 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4833 PetscCall(DMPforestGetPlex(dm,&plex)); 4834 PetscCall(DMGetCoordinateDM(plex,cdm)); 4835 PetscCall(PetscObjectReference((PetscObject)*cdm)); 4836 PetscFunctionReturn(0); 4837 } 4838 4839 #define VecViewLocal_pforest _append_pforest(VecViewLocal) 4840 static PetscErrorCode VecViewLocal_pforest(Vec vec,PetscViewer viewer) 4841 { 4842 DM dm, plex; 4843 4844 PetscFunctionBegin; 4845 PetscCall(VecGetDM(vec,&dm)); 4846 PetscCall(DMPforestGetPlex(dm,&plex)); 4847 PetscCall(VecSetDM(vec,plex)); 4848 PetscCall(VecView_Plex_Local(vec,viewer)); 4849 PetscCall(VecSetDM(vec,dm)); 4850 PetscFunctionReturn(0); 4851 } 4852 4853 #define VecView_pforest _append_pforest(VecView) 4854 static PetscErrorCode VecView_pforest(Vec vec,PetscViewer viewer) 4855 { 4856 DM dm, plex; 4857 4858 PetscFunctionBegin; 4859 PetscCall(VecGetDM(vec,&dm)); 4860 PetscCall(DMPforestGetPlex(dm,&plex)); 4861 PetscCall(VecSetDM(vec,plex)); 4862 PetscCall(VecView_Plex(vec,viewer)); 4863 PetscCall(VecSetDM(vec,dm)); 4864 PetscFunctionReturn(0); 4865 } 4866 4867 #define VecView_pforest_Native _infix_pforest(VecView,_Native) 4868 static PetscErrorCode VecView_pforest_Native(Vec vec,PetscViewer viewer) 4869 { 4870 DM dm, plex; 4871 4872 PetscFunctionBegin; 4873 PetscCall(VecGetDM(vec,&dm)); 4874 PetscCall(DMPforestGetPlex(dm,&plex)); 4875 PetscCall(VecSetDM(vec,plex)); 4876 PetscCall(VecView_Plex_Native(vec,viewer)); 4877 PetscCall(VecSetDM(vec,dm)); 4878 PetscFunctionReturn(0); 4879 } 4880 4881 #define VecLoad_pforest _append_pforest(VecLoad) 4882 static PetscErrorCode VecLoad_pforest(Vec vec,PetscViewer viewer) 4883 { 4884 DM dm, plex; 4885 4886 PetscFunctionBegin; 4887 PetscCall(VecGetDM(vec,&dm)); 4888 PetscCall(DMPforestGetPlex(dm,&plex)); 4889 PetscCall(VecSetDM(vec,plex)); 4890 PetscCall(VecLoad_Plex(vec,viewer)); 4891 PetscCall(VecSetDM(vec,dm)); 4892 PetscFunctionReturn(0); 4893 } 4894 4895 #define VecLoad_pforest_Native _infix_pforest(VecLoad,_Native) 4896 static PetscErrorCode VecLoad_pforest_Native(Vec vec,PetscViewer viewer) 4897 { 4898 DM dm, plex; 4899 4900 PetscFunctionBegin; 4901 PetscCall(VecGetDM(vec,&dm)); 4902 PetscCall(DMPforestGetPlex(dm,&plex)); 4903 PetscCall(VecSetDM(vec,plex)); 4904 PetscCall(VecLoad_Plex_Native(vec,viewer)); 4905 PetscCall(VecSetDM(vec,dm)); 4906 PetscFunctionReturn(0); 4907 } 4908 4909 #define DMCreateGlobalVector_pforest _append_pforest(DMCreateGlobalVector) 4910 static PetscErrorCode DMCreateGlobalVector_pforest(DM dm,Vec *vec) 4911 { 4912 PetscFunctionBegin; 4913 PetscCall(DMCreateGlobalVector_Section_Private(dm,vec)); 4914 /* PetscCall(VecSetOperation(*vec, VECOP_DUPLICATE, (void(*)(void)) VecDuplicate_MPI_DM)); */ 4915 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecView_pforest)); 4916 PetscCall(VecSetOperation(*vec, VECOP_VIEWNATIVE, (void (*)(void))VecView_pforest_Native)); 4917 PetscCall(VecSetOperation(*vec, VECOP_LOAD, (void (*)(void))VecLoad_pforest)); 4918 PetscCall(VecSetOperation(*vec, VECOP_LOADNATIVE, (void (*)(void))VecLoad_pforest_Native)); 4919 PetscFunctionReturn(0); 4920 } 4921 4922 #define DMCreateLocalVector_pforest _append_pforest(DMCreateLocalVector) 4923 static PetscErrorCode DMCreateLocalVector_pforest(DM dm,Vec *vec) 4924 { 4925 PetscFunctionBegin; 4926 PetscCall(DMCreateLocalVector_Section_Private(dm,vec)); 4927 PetscCall(VecSetOperation(*vec, VECOP_VIEW, (void (*)(void))VecViewLocal_pforest)); 4928 PetscFunctionReturn(0); 4929 } 4930 4931 #define DMCreateMatrix_pforest _append_pforest(DMCreateMatrix) 4932 static PetscErrorCode DMCreateMatrix_pforest(DM dm,Mat *mat) 4933 { 4934 DM plex; 4935 4936 PetscFunctionBegin; 4937 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4938 PetscCall(DMPforestGetPlex(dm,&plex)); 4939 if (plex->prealloc_only != dm->prealloc_only) plex->prealloc_only = dm->prealloc_only; /* maybe this should go into forest->plex */ 4940 PetscCall(DMCreateMatrix(plex,mat)); 4941 PetscCall(MatSetDM(*mat,dm)); 4942 PetscFunctionReturn(0); 4943 } 4944 4945 #define DMProjectFunctionLocal_pforest _append_pforest(DMProjectFunctionLocal) 4946 static PetscErrorCode DMProjectFunctionLocal_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, InsertMode mode, Vec localX) 4947 { 4948 DM plex; 4949 4950 PetscFunctionBegin; 4951 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4952 PetscCall(DMPforestGetPlex(dm,&plex)); 4953 PetscCall(DMProjectFunctionLocal(plex,time,funcs,ctxs,mode,localX)); 4954 PetscFunctionReturn(0); 4955 } 4956 4957 #define DMProjectFunctionLabelLocal_pforest _append_pforest(DMProjectFunctionLabelLocal) 4958 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) 4959 { 4960 DM plex; 4961 4962 PetscFunctionBegin; 4963 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4964 PetscCall(DMPforestGetPlex(dm,&plex)); 4965 PetscCall(DMProjectFunctionLabelLocal(plex,time,label,numIds,ids,Ncc,comps,funcs,ctxs,mode,localX)); 4966 PetscFunctionReturn(0); 4967 } 4968 4969 #define DMProjectFieldLocal_pforest _append_pforest(DMProjectFieldLocal) 4970 PetscErrorCode DMProjectFieldLocal_pforest(DM dm, PetscReal time, Vec localU,void (**funcs) (PetscInt, PetscInt, PetscInt, 4971 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 4972 const PetscInt[], const PetscInt[], const PetscScalar[], const PetscScalar[], const PetscScalar[], 4973 PetscReal, const PetscReal[], PetscInt, const PetscScalar[], PetscScalar[]),InsertMode mode, Vec localX) 4974 { 4975 DM plex; 4976 4977 PetscFunctionBegin; 4978 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4979 PetscCall(DMPforestGetPlex(dm,&plex)); 4980 PetscCall(DMProjectFieldLocal(plex,time,localU,funcs,mode,localX)); 4981 PetscFunctionReturn(0); 4982 } 4983 4984 #define DMComputeL2Diff_pforest _append_pforest(DMComputeL2Diff) 4985 PetscErrorCode DMComputeL2Diff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal *diff) 4986 { 4987 DM plex; 4988 4989 PetscFunctionBegin; 4990 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 4991 PetscCall(DMPforestGetPlex(dm,&plex)); 4992 PetscCall(DMComputeL2Diff(plex,time,funcs,ctxs,X,diff)); 4993 PetscFunctionReturn(0); 4994 } 4995 4996 #define DMComputeL2FieldDiff_pforest _append_pforest(DMComputeL2FieldDiff) 4997 PetscErrorCode DMComputeL2FieldDiff_pforest(DM dm, PetscReal time, PetscErrorCode (**funcs) (PetscInt, PetscReal, const PetscReal [], PetscInt, PetscScalar *, void*), void **ctxs, Vec X, PetscReal diff[]) 4998 { 4999 DM plex; 5000 5001 PetscFunctionBegin; 5002 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 5003 PetscCall(DMPforestGetPlex(dm,&plex)); 5004 PetscCall(DMComputeL2FieldDiff(plex,time,funcs,ctxs,X,diff)); 5005 PetscFunctionReturn(0); 5006 } 5007 5008 #define DMCreatelocalsection_pforest _append_pforest(DMCreatelocalsection) 5009 static PetscErrorCode DMCreatelocalsection_pforest(DM dm) 5010 { 5011 DM plex; 5012 PetscSection section; 5013 5014 PetscFunctionBegin; 5015 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 5016 PetscCall(DMPforestGetPlex(dm,&plex)); 5017 PetscCall(DMGetLocalSection(plex,§ion)); 5018 PetscCall(DMSetLocalSection(dm,section)); 5019 PetscFunctionReturn(0); 5020 } 5021 5022 #define DMCreateDefaultConstraints_pforest _append_pforest(DMCreateDefaultConstraints) 5023 static PetscErrorCode DMCreateDefaultConstraints_pforest(DM dm) 5024 { 5025 DM plex; 5026 Mat mat; 5027 Vec bias; 5028 PetscSection section; 5029 5030 PetscFunctionBegin; 5031 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 5032 PetscCall(DMPforestGetPlex(dm,&plex)); 5033 PetscCall(DMGetDefaultConstraints(plex,§ion,&mat,&bias)); 5034 PetscCall(DMSetDefaultConstraints(dm,section,mat,bias)); 5035 PetscFunctionReturn(0); 5036 } 5037 5038 #define DMGetDimPoints_pforest _append_pforest(DMGetDimPoints) 5039 static PetscErrorCode DMGetDimPoints_pforest(DM dm, PetscInt dim, PetscInt *cStart, PetscInt *cEnd) 5040 { 5041 DM plex; 5042 5043 PetscFunctionBegin; 5044 PetscValidHeaderSpecific(dm,DM_CLASSID,1); 5045 PetscCall(DMPforestGetPlex(dm,&plex)); 5046 PetscCall(DMGetDimPoints(plex,dim,cStart,cEnd)); 5047 PetscFunctionReturn(0); 5048 } 5049 5050 /* Need to forward declare */ 5051 #define DMInitialize_pforest _append_pforest(DMInitialize) 5052 static PetscErrorCode DMInitialize_pforest(DM dm); 5053 5054 #define DMClone_pforest _append_pforest(DMClone) 5055 static PetscErrorCode DMClone_pforest(DM dm, DM *newdm) 5056 { 5057 PetscFunctionBegin; 5058 PetscCall(DMClone_Forest(dm,newdm)); 5059 PetscCall(DMInitialize_pforest(*newdm)); 5060 PetscFunctionReturn(0); 5061 } 5062 5063 #define DMForestCreateCellChart_pforest _append_pforest(DMForestCreateCellChart) 5064 static PetscErrorCode DMForestCreateCellChart_pforest(DM dm, PetscInt *cStart, PetscInt *cEnd) 5065 { 5066 DM_Forest *forest; 5067 DM_Forest_pforest *pforest; 5068 PetscInt overlap; 5069 5070 PetscFunctionBegin; 5071 PetscCall(DMSetUp(dm)); 5072 forest = (DM_Forest*) dm->data; 5073 pforest = (DM_Forest_pforest*) forest->data; 5074 *cStart = 0; 5075 PetscCall(DMForestGetPartitionOverlap(dm,&overlap)); 5076 if (overlap && pforest->ghost) { 5077 *cEnd = pforest->forest->local_num_quadrants + pforest->ghost->proc_offsets[pforest->forest->mpisize]; 5078 } else { 5079 *cEnd = pforest->forest->local_num_quadrants; 5080 } 5081 PetscFunctionReturn(0); 5082 } 5083 5084 #define DMForestCreateCellSF_pforest _append_pforest(DMForestCreateCellSF) 5085 static PetscErrorCode DMForestCreateCellSF_pforest(DM dm, PetscSF *cellSF) 5086 { 5087 DM_Forest *forest; 5088 DM_Forest_pforest *pforest; 5089 PetscMPIInt rank; 5090 PetscInt overlap; 5091 PetscInt cStart, cEnd, cLocalStart, cLocalEnd; 5092 PetscInt nRoots, nLeaves, *mine = NULL; 5093 PetscSFNode *remote = NULL; 5094 PetscSF sf; 5095 5096 PetscFunctionBegin; 5097 PetscCall(DMForestGetCellChart(dm,&cStart,&cEnd)); 5098 forest = (DM_Forest*) dm->data; 5099 pforest = (DM_Forest_pforest*) forest->data; 5100 nRoots = cEnd - cStart; 5101 cLocalStart = pforest->cLocalStart; 5102 cLocalEnd = pforest->cLocalEnd; 5103 nLeaves = 0; 5104 PetscCall(DMForestGetPartitionOverlap(dm,&overlap)); 5105 PetscCallMPI(MPI_Comm_rank(PetscObjectComm((PetscObject)dm),&rank)); 5106 if (overlap && pforest->ghost) { 5107 PetscSFNode *mirror; 5108 p4est_quadrant_t *mirror_array; 5109 PetscInt nMirror, nGhostPre, nSelf, q; 5110 void **mirrorPtrs; 5111 5112 nMirror = (PetscInt) pforest->ghost->mirrors.elem_count; 5113 nSelf = cLocalEnd - cLocalStart; 5114 nLeaves = nRoots - nSelf; 5115 nGhostPre = (PetscInt) pforest->ghost->proc_offsets[rank]; 5116 PetscCall(PetscMalloc1(nLeaves,&mine)); 5117 PetscCall(PetscMalloc1(nLeaves,&remote)); 5118 PetscCall(PetscMalloc2(nMirror,&mirror,nMirror,&mirrorPtrs)); 5119 mirror_array = (p4est_quadrant_t*) pforest->ghost->mirrors.array; 5120 for (q = 0; q < nMirror; q++) { 5121 p4est_quadrant_t *mir = &(mirror_array[q]); 5122 5123 mirror[q].rank = rank; 5124 mirror[q].index = (PetscInt) mir->p.piggy3.local_num + cLocalStart; 5125 mirrorPtrs[q] = (void*) &(mirror[q]); 5126 } 5127 PetscStackCallP4est(p4est_ghost_exchange_custom,(pforest->forest,pforest->ghost,sizeof(PetscSFNode),mirrorPtrs,remote)); 5128 PetscCall(PetscFree2(mirror,mirrorPtrs)); 5129 for (q = 0; q < nGhostPre; q++) mine[q] = q; 5130 for (; q < nLeaves; q++) mine[q] = (q - nGhostPre) + cLocalEnd; 5131 } 5132 PetscCall(PetscSFCreate(PetscObjectComm((PetscObject)dm),&sf)); 5133 PetscCall(PetscSFSetGraph(sf,nRoots,nLeaves,mine,PETSC_OWN_POINTER,remote,PETSC_OWN_POINTER)); 5134 *cellSF = sf; 5135 PetscFunctionReturn(0); 5136 } 5137 5138 static PetscErrorCode DMCreateNeumannOverlap_pforest(DM dm, IS* ovl, Mat *J, PetscErrorCode (**setup)(Mat, PetscReal, Vec, Vec, PetscReal, IS, void*), void **setup_ctx) 5139 { 5140 DM plex; 5141 5142 PetscFunctionBegin; 5143 PetscCall(DMPforestGetPlex(dm,&plex)); 5144 PetscCall(DMCreateNeumannOverlap_Plex(plex,ovl,J,setup,setup_ctx)); 5145 if (!*setup) { 5146 PetscCall(PetscObjectQueryFunction((PetscObject)dm, "MatComputeNeumannOverlap_C", setup)); 5147 if (*setup) { 5148 PetscCall(PetscObjectCompose((PetscObject)*ovl, "_DM_Original_HPDDM", (PetscObject)dm)); 5149 } 5150 } 5151 PetscFunctionReturn(0); 5152 } 5153 5154 static PetscErrorCode DMInitialize_pforest(DM dm) 5155 { 5156 PetscFunctionBegin; 5157 dm->ops->setup = DMSetUp_pforest; 5158 dm->ops->view = DMView_pforest; 5159 dm->ops->clone = DMClone_pforest; 5160 dm->ops->createinterpolation = DMCreateInterpolation_pforest; 5161 dm->ops->createinjection = DMCreateInjection_pforest; 5162 dm->ops->setfromoptions = DMSetFromOptions_pforest; 5163 dm->ops->createcoordinatedm = DMCreateCoordinateDM_pforest; 5164 dm->ops->createglobalvector = DMCreateGlobalVector_pforest; 5165 dm->ops->createlocalvector = DMCreateLocalVector_pforest; 5166 dm->ops->creatematrix = DMCreateMatrix_pforest; 5167 dm->ops->projectfunctionlocal = DMProjectFunctionLocal_pforest; 5168 dm->ops->projectfunctionlabellocal = DMProjectFunctionLabelLocal_pforest; 5169 dm->ops->projectfieldlocal = DMProjectFieldLocal_pforest; 5170 dm->ops->createlocalsection = DMCreatelocalsection_pforest; 5171 dm->ops->createdefaultconstraints = DMCreateDefaultConstraints_pforest; 5172 dm->ops->computel2diff = DMComputeL2Diff_pforest; 5173 dm->ops->computel2fielddiff = DMComputeL2FieldDiff_pforest; 5174 dm->ops->getdimpoints = DMGetDimPoints_pforest; 5175 5176 PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_plex_pforest) "_C",DMConvert_plex_pforest)); 5177 PetscCall(PetscObjectComposeFunction((PetscObject)dm,PetscStringize(DMConvert_pforest_plex) "_C",DMConvert_pforest_plex)); 5178 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMCreateNeumannOverlap_C",DMCreateNeumannOverlap_pforest)); 5179 PetscCall(PetscObjectComposeFunction((PetscObject)dm,"DMPlexGetOverlap_C",DMForestGetPartitionOverlap)); 5180 PetscFunctionReturn(0); 5181 } 5182 5183 #define DMCreate_pforest _append_pforest(DMCreate) 5184 PETSC_EXTERN PetscErrorCode DMCreate_pforest(DM dm) 5185 { 5186 DM_Forest *forest; 5187 DM_Forest_pforest *pforest; 5188 5189 PetscFunctionBegin; 5190 PetscCall(PetscP4estInitialize()); 5191 PetscCall(DMCreate_Forest(dm)); 5192 PetscCall(DMInitialize_pforest(dm)); 5193 PetscCall(DMSetDimension(dm,P4EST_DIM)); 5194 5195 /* set forest defaults */ 5196 PetscCall(DMForestSetTopology(dm,"unit")); 5197 PetscCall(DMForestSetMinimumRefinement(dm,0)); 5198 PetscCall(DMForestSetInitialRefinement(dm,0)); 5199 PetscCall(DMForestSetMaximumRefinement(dm,P4EST_QMAXLEVEL)); 5200 PetscCall(DMForestSetGradeFactor(dm,2)); 5201 PetscCall(DMForestSetAdjacencyDimension(dm,0)); 5202 PetscCall(DMForestSetPartitionOverlap(dm,0)); 5203 5204 /* create p4est data */ 5205 PetscCall(PetscNewLog(dm,&pforest)); 5206 5207 forest = (DM_Forest*) dm->data; 5208 forest->data = pforest; 5209 forest->destroy = DMForestDestroy_pforest; 5210 forest->ftemplate = DMForestTemplate_pforest; 5211 forest->transfervec = DMForestTransferVec_pforest; 5212 forest->transfervecfrombase = DMForestTransferVecFromBase_pforest; 5213 forest->createcellchart = DMForestCreateCellChart_pforest; 5214 forest->createcellsf = DMForestCreateCellSF_pforest; 5215 forest->clearadaptivityforest = DMForestClearAdaptivityForest_pforest; 5216 forest->getadaptivitysuccess = DMForestGetAdaptivitySuccess_pforest; 5217 pforest->topo = NULL; 5218 pforest->forest = NULL; 5219 pforest->ghost = NULL; 5220 pforest->lnodes = NULL; 5221 pforest->partition_for_coarsening = PETSC_TRUE; 5222 pforest->coarsen_hierarchy = PETSC_FALSE; 5223 pforest->cLocalStart = -1; 5224 pforest->cLocalEnd = -1; 5225 pforest->labelsFinalized = PETSC_FALSE; 5226 pforest->ghostName = NULL; 5227 PetscFunctionReturn(0); 5228 } 5229 5230 #endif /* defined(PETSC_HAVE_P4EST) */ 5231