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