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