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